首页
📷在线壁纸
🎬娱乐天地
🔖友情链接
更多
📝留言板
Search
1
【javascript】JS-向当前url追加参数
2,344 阅读
2
【PHP】生成随机昵称
2,201 阅读
3
【PHP】判断一个字符串是否属于序列化后的数据
2,023 阅读
4
【css】html+css给文章页,做阅读全文
1,974 阅读
5
【PHP】 设计模式(23种)
1,908 阅读
📂默认分类
💓typecho
🏳️🌈代码改变世界
🍇 mysql
🍈 Winform
🍓 golang
🍉 设计模式
🥝 PHP
🍎 python
🍊 nginx
🍋 网络安全
🍍 javascript
🫑 database
🍡 AI
🍭文艺范
🍏mac
登录
Search
标签搜索
php
typecho
代码注释
redis
mysql
go
golang
nginx
thinkphp
docker
gin
linux
curl
html
mamp
算法
短网址
构造函数
webhook
代码片段
依然范儿特西
累计撰写
145
篇文章
累计收到
1
条评论
首页
栏目
📂默认分类
💓typecho
🏳️🌈代码改变世界
🍇 mysql
🍈 Winform
🍓 golang
🍉 设计模式
🥝 PHP
🍎 python
🍊 nginx
🍋 网络安全
🍍 javascript
🫑 database
🍡 AI
🍭文艺范
🍏mac
页面
📷在线壁纸
🎬娱乐天地
🔖友情链接
📝留言板
搜索到
4
篇与
的结果
2023-10-10
Gin 框架在中间件中获取 response body 的方法
在写一个Gin框架日志中间件的时候,需要记录请求和响应相关的一些数据,例如请求参数、请求方法、请求时间、请求头、耗时、响应状态码、响应数据等,gin为获取这些数据基本都提供了现成的方法,但是获取响应数据还是有一定难度和复杂度的。那么,该如何获取响应数据也就是 response body 呢?先上代码。代码示例1、先写一个 middleware ,简单打印一下 response bodypackage middleware import ( "bytes" "fmt" "github.com/gin-gonic/gin" ) //自定义一个结构体,实现 gin.ResponseWriter interface type responseWriter struct { gin.ResponseWriter b *bytes.Buffer } //重写 Write([]byte) (int, error) 方法 func (w responseWriter) Write(b []byte) (int, error) { //向一个bytes.buffer中写一份数据来为获取body使用 w.b.Write(b) //完成gin.Context.Writer.Write()原有功能 return w.ResponseWriter.Write(b) } func PrintResponse(c *gin.Context) { writer := responseWriter{ c.Writer, bytes.NewBuffer([]byte{}), } c.Writer = writer c.Next() fmt.Println("response body:" + writer.b.String()) } 2、引用 middleware ,看看效果package main import ( "github.com/gin-gonic/gin" "hello/middleware" "net/http" ) func main() { r := gin.New() //添加获取响应内容 middleware r.Use(middleware.PrintResponse) r.GET("/test", func(c *gin.Context) { c.JSON(http.StatusOK, gin.H{"name": "laofan"}) }) // Listen and Server in 0.0.0.0:8080 r.Run(":8080") } 打开浏览器访问http://127.0.0.1:8080/test ,即可在控制台中看到 response body 的输出内容response body:{"name":"laofan"}原理通过上面的代码可以看出,gin 通过调用如下方法写入了 response bodyc.JSON(http.StatusOK, gin.H{"name": "laofan"})追进 JSON 方法,源码如下,调用了 Render 方法package gin func (c *Context) JSON(code int, obj interface{}) { c.Render(code, render.JSON{Data: obj}) }追进 Render 方法, 可以看出 gin.Context.Writer 作为参数传给了 r.Render() 方法,这里形参 r 的实参为 render.JSON{Data: obj} ,所以实际调用的是 func (r JSON) Render(w http.ResponseWriter) 方法。package gin // Render writes the response headers and calls render.Render to render data. func (c *Context) Render(code int, r render.Render) { c.Status(code) if !bodyAllowedForStatus(code) { r.WriteContentType(c.Writer) c.Writer.WriteHeaderNow() return } if err := r.Render(c.Writer); err != nil { panic(err) } } func (r JSON) Render(w http.ResponseWriter) 源码如下package render // Render (JSON) writes data with custom ContentType. func (r JSON) Render(w http.ResponseWriter) (err error) { if err = WriteJSON(w, r.Data); err != nil { panic(err) } return } // WriteJSON marshals the given interface object and writes it with custom ContentType. func WriteJSON(w http.ResponseWriter, obj interface{}) error { writeContentType(w, jsonContentType) jsonBytes, err := json.Marshal(obj) if err != nil { return err } _, err = w.Write(jsonBytes) return err } 在 func (r JSON) Render() 方法中,gin.Context.Writer 被传到了 WriteJSON() 方法中,最终写入数据调用的是 gin.Context.Writer.Write() 方法。gin.ResponseWriter 源码如下package gin type Context struct { //... writermem responseWriter Writer ResponseWriter //... } // ResponseWriter ... type ResponseWriter interface { //... http.ResponseWriter //... } 可以看出 gin.Context.Writer 类型为 interface gin.ResponseWriter。package http type ResponseWriter interface { //... Write([]byte) (int, error) //... } 要实现 gin.ResponseWriter 接口,必须实现Write([]byte) (int, error) 方法。所以写入 response body 调用的是 gin.Context.Writer.Write() 方法,gin.Context.Writer 需要是type gin.ResponseWriter interface 的一个具体实现。到此,可以看出上面代码示例的思路:实现 type gin.ResponseWriter interface 并重写 Write([]byte) (int, error) 方法,该方法在实现 gin.Context.Writer.Write() 原有功能的同时,再向一个 bytes.buffer 中写一份数据来用于获取 response body 使用。
2023年10月10日
5 阅读
0 评论
0 点赞
2021-11-24
Golang 实现结构体数组按多字段排序
php 排序写法近期因项目重构(php->golang),涉及到一些将对象列表中的对象按不同的字段(属性)排序;在 php 中,可以使用 usort + 自定义的排序函数轻松实现;PHP usort 官方文档下面我们先看一个在 php 中的例子: 下面是一个待排序待数组<?php $result = array( array( "val" => "f", "mtime" => 1595144638, "orderval"=>4 ), array( "val" => "d", "mtime" => 1595144646, "orderval"=>2 ), array( "val" => "a", "mtime" => 1595144648, "orderval"=>8 ), array( "val" => "t", "mtime" => 1595144648, "orderval"=>5 ), array( "val" => "e", "mtime" => 1595144650, "orderval"=>3 ) );我们目前待目标是将该数组中待对象按 mtime 从大到小排序;如果 mtime 字段的值相等,则按 orderval 从大到小排,最终想要的结果为:e,a,t,d,f[ {"val"=>"e","mtime"=>1595144650,"orderval"=>3}, {"val"=>"a","mtime"=>1595144648,"orderval"=>8}, {"val"=>"t","mtime"=>1595144648,"orderval"=>5}, {"val"=>"d","mtime"=>1595144646,"orderval"=>2}, {"val"=>"f","mtime"=>1595144638,"orderval"=>4} ] 我们首先定义一个自定义函数,然后巧妙使用 usort 函数去调用的自定义函数,最终实现目标,直接上代码:php $result = array( array( "val" => "f", "mtime" => 1595144638, "orderval"=>4 ), array( "val" => "d", "mtime" => 1595144646, "orderval"=>2 ), array( "val" => "a", "mtime" => 1595144648, "orderval"=>8 ), array( "val" => "t", "mtime" => 1595144648, "orderval"=>5 ), array( "val" => "e", "mtime" => 1595144650, "orderval"=>3 ) ); //按mtime 从大到小;如果mtime 相等,则按orderval 从大到小; usort($result, function ($v1, $v2) { if ($v1['mtime'] < $v2['mtime'] || ($v1['mtime'] == $v2['mtime'] && $v1['orderval'] < $v2['orderval'])) { return 1; } else { return -1; } }); var_dump($result); 运行结果:array(5) { [0]=> array(3) { ["val"]=> string(1) "e" ["mtime"]=> int(1595144650) ["orderval"]=> int(3) } [1]=> array(3) { ["val"]=> string(1) "a" ["mtime"]=> int(1595144648) ["orderval"]=> int(8) } [2]=> array(3) { ["val"]=> string(1) "t" ["mtime"]=> int(1595144648) ["orderval"]=> int(5) } [3]=> array(3) { ["val"]=> string(1) "d" ["mtime"]=> int(1595144646) ["orderval"]=> int(2) } [4]=> array(3) { ["val"]=> string(1) "f" ["mtime"]=> int(1595144638) ["orderval"]=> int(4) } }那么同样的功能,如果要用 golang 来实现,应如何办呢?golang 排序下面我们首先讲讲 golang 官方对排序 对支持,然后给出具体对例子;package main import ( "fmt" "sort" ) type Obj struct { Var string `json:"var"` Mtime int `json:"mtime"` Orderval int `json:"orderval"` } type List []Obj func (p List) Len() int { return len(p) } // 此处排序是从大到小的, 如果想升序,可以把此方法里的 判定 改为 相反的判定即可 func (p List) Less(i, j int) bool { if p[i].Mtime > p[j].Mtime { return true } if p[i].Mtime < p[j].Mtime { return false } return p[i].Orderval > p[j].Orderval } func (p List) Swap(i, j int) { p[i], p[j] = p[j], p[i] } func (p *List) Sort() { sort.Sort(p) } func main() { s := List{{"f", 1595144638, 4}, {"d", 1595144646, 2}, {"a", 1595144648, 8}, {"t", 1595144648, 5}, {"e", 1595144650, 3}} fmt.Println(s) s.Sort() fmt.Println(s) } // 如果想使用传入的方法来写,可以把main 方法 的写法改为下边这个 //func toSortAsc(UserList []Obj)[]Obj{ // s := List{} // for _,v := range UserList{ // s = append(s,v) // } // s.Sort() // return s //} 再举一个简单的例子package main import ( "fmt" "sort" ) type Instance struct { Domain string `json:"domain"` Ip string `json:"ip"` Containers []string `json:"containers,omitempty"` } func main() { instances := make([]*Instance, 0, 10) i1 := &Instance{} i1.Domain = "zhap" i1.Ip = "1" instances = append(instances, i1) i2 := &Instance{} i2.Domain = "abc" i2.Ip = "2" instances = append(instances, i2) i3 := &Instance{} i3.Domain = "mid" i3.Ip = "3" instances = append(instances, i3) fmt.Println("排序前 ") for _, v := range instances { fmt.Println(*v) } sort.Slice(instances, func(i, j int) bool { return instances[i].Domain < instances[j].Domain }) fmt.Println("排序后 ") for _, v := range instances { fmt.Println(*v) } }
2021年11月24日
740 阅读
0 评论
2 点赞
2021-09-30
Golang之log(如何将日志写到指定文件里面)
对于Go语言的日志来说,如何将log写到指定的文件里面,下面是一个例子。如何将log 写入到指定的文件中?方法一:package main import ( "log" "os" "time" ) func init() { file := "./" +"log"+ ".txt" logFile, err := os.OpenFile(file, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0766) if err != nil { panic(err) } log.SetOutput(logFile) // 将文件设置为log输出的文件 log.SetPrefix("[logTool]") log.SetFlags(log.LstdFlags | log.Lshortfile | log.LUTC) return } func main() { log.Println("Hello laofan!") // log 还是可以作为输出的前缀 return }output:// message.txt里面 显示 [logTool]2021/09/30 15:30:05 log.go:24: Hello laofan! 方法二:package main import ( "log" "os" "time" ) var loger *log.Logger func init() { file := "./" + time.Now().Format("20210930") + ".txt" logFile, err := os.OpenFile(file, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0766) if err != nil { panic(err) } loger = log.New(logFile, "[logTool]",log.LstdFlags | log.Lshortfile | log.LUTC) // 将文件设置为loger作为输出 return } func main() { // 使用的时候,需要采用loger作为输出的前缀 loger.Println("Hello:laofan!") return } output:// message.txt里面 显示 [logTool]2021/09/30 15:35:20 log.go:24: Hello laofan! `` 灰子作于二零二一年九月三十日。
2021年09月30日
827 阅读
0 评论
0 点赞
2021-09-01
Golang 获取https证书信息、过期信息
package main import ( "crypto/tls" "fmt" "net/http" ) func main() { tr := &http.Transport{ TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, } client := &http.Client{Transport: tr} seedUrl := "https://richerdyoung.com" resp, err := client.Get(seedUrl) defer resp.Body.Close() if err != nil { fmt.Errorf(seedUrl," 请求失败") panic(err) } //fmt.Println(resp.TLS.PeerCertificates[0]) certInfo:=resp.TLS.PeerCertificates[0] fmt.Println("过期时间:",certInfo.NotAfter) fmt.Println("组织信息:",certInfo.Subject) } 运行结果过期时间: 2021-09-02 07:27:20 +0000 UTC 组织信息: CN=www.richerdyoung.com
2021年09月01日
324 阅读
0 评论
1 点赞