blog
blog copied to clipboard
Go语言动手写Web框架 - Gee第二天 上下文Context | 极客兔兔
https://geektutu.com/post/gee-day2.html
7天用 Go语言 从零实现Web框架教程(7 days implement golang web framework from scratch tutorial),用 Go语言/golang 动手写Web框架,从零实现一个Web框架,从零设计一个Web框架。本文介绍了请求上下文(Context)的设计理念,封装了返回JSON/String/Data/HTML等类型响应的方法。
赞一下,非常6
正确的调用顺序应该是Header().Set 然后WriteHeader() 最后是Write()
@walkmiao 正确的调用顺序应该是Header().Set 然后WriteHeader() 最后是Write()
感谢指出,在 WriteHeader()
后调用 Header().Set
是不会生效的,已经更正~
@geektutu
@walkmiao 正确的调用顺序应该是Header().Set 然后WriteHeader() 最后是Write()
感谢指出,在
WriteHeader()
后调用Header().Set
是不会生效的,已经更正~
感谢分享的教程
大佬 JSON()这里有点问题
func (c *Context) JSON(code int, obj interface{}) {
c.SetHeader("Content-Type", "application/json")
c.Status(code)
// c.StatusCode = code
// c.Writer.WriteHeader(code)
encoder := json.NewEncoder(c.Writer)
if err := encoder.Encode(obj); err != nil {
http.Error(c.Writer, err.Error(), 500)
// w.Header().Set("Content-Type", "text/plain; charset=utf-8")
// w.Header().Set("X-Content-Type-Options", "nosniff")
// w.WriteHeader(code)
// fmt.Fprintln(w, error)
}
}
如果err!=nil的话http.Error(c.Writer, err.Error(), 500)这里是不起作用的,因为前面已经执行了WriteHeader(code),那么返回码将不会再更改http.Error(c.Writer, err.Error(), 500)里面的w.WriteHeader(code)、w.Header().Set()不起作用,而且encoder.Encode(obj)相当于调用了Write(),http.Error(c.Writer, err.Error(), 500)里面的WriteHeader、Header().Set()操作都是无效的。我看了gin的代码,如果encoder.Encode(obj)这里报错的话是直接panic,感觉这里如果err!=nil的话确实不好处理
附上gin的代码 render/json.go 56行
// 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
}
// WriteContentType (JSON) writes JSON ContentType.
func (r JSON) WriteContentType(w http.ResponseWriter) {
writeContentType(w, jsonContentType)
}
// WriteJSON marshals the given interface object and writes it with custom ContentType.
func WriteJSON(w http.ResponseWriter, obj interface{}) error {
writeContentType(w, jsonContentType)
encoder := json.NewEncoder(w)
err := encoder.Encode(&obj)
return err
}
@xiaoxfan 非常感谢指出了这个问题,之前的实现没有注意到这个问题。看到这里的童鞋可以看看gin的实现,地址贴在这里render/json.go#L56
day2-context/gee/router.go文件的第18行的正确写法是handler(c.Writer, c.Req),在handle函数中
感谢教程!我在使用curl命令 curl "http://localhost:9999/login" -X POST -d 'username=geektutu&password=1234' 时无法解析出传递的参数,并且显示'password' 不是内部或外部命令,也不是可运行的程序或批处理文件。这是什么原因?
@lorenwe day2-context/gee/router.go文件的第18行的正确写法是handler(c.Writer, c.Req),在handle函数中
文章的没错, 你是不是 gee.go中 type HandlerFunc func(*Context)
没改, 还是写的type HandlerFunc func(w http.ResponseWriter, r *http.Request)
?
感谢手把手的教我框架的设计思想 让我对人生又重新燃起了希望
兔兔,兔兔我爱你,我要给你生🐒(虽然我是男的)
@Pissssofshit 这。。。公司联谊你可以的。😉
@Pissssofshit 这。。。公司联谊你可以的。😉
嘿嘿嘿,gay里gay气
@Leoooo-tqp 感谢教程!我在使用curl命令 curl "http://localhost:9999/login" -X POST -d 'username=geektutu&password=1234' 时无法解析出传递的参数,并且显示'password' 不是内部或外部命令,也不是可运行的程序或批处理文件。这是什么原因?
用双引号
非常棒,手敲一遍,感触颇深
@walkmiao
@geektutu
@walkmiao 正确的调用顺序应该是Header().Set 然后WriteHeader() 最后是Write()
感谢指出,在
WriteHeader()
后调用Header().Set
是不会生效的,已经更正~感谢分享的教程
这个调用顺序是说哪里啊
@Leoooo-tqp 感谢教程!我在使用curl命令 curl "http://localhost:9999/login" -X POST -d 'username=geektutu&password=1234' 时无法解析出传递的参数,并且显示'password' 不是内部或外部命令,也不是可运行的程序或批处理文件。这是什么原因?
正确调用姿势:curl --location --request POST '127.0.0.1:9999/login'
--form 'password="张三"'
--form 'username="李思"'
感谢分享~
感谢分享~
@DiDiDaDiDiDa 感谢认可,笔芯~ 😄
@Leoooo-tqp 感谢教程!我在使用curl命令 curl "http://localhost:9999/login" -X POST -d 'username=geektutu&password=1234' 时无法解析出传递的参数,并且显示'password' 不是内部或外部命令,也不是可运行的程序或批处理文件。这是什么原因?
我也有这个,难道是命令不一致吗
@jianhuacc
@Leoooo-tqp 感谢教程!我在使用curl命令 curl "http://localhost:9999/login" -X POST -d 'username=geektutu&password=1234' 时无法解析出传递的参数,并且显示'password' 不是内部或外部命令,也不是可运行的程序或批处理文件。这是什么原因?
我也有这个,难道是命令不一致吗
用双引号,curl "http://localhost:9999/login" -X POST -d "username=geektutu&password=1234"
@HongTian
@jianhuacc
@Leoooo-tqp 感谢教程!我在使用curl命令 curl "http://localhost:9999/login" -X POST -d 'username=geektutu&password=1234' 时无法解析出传递的参数,并且显示'password' 不是内部或外部命令,也不是可运行的程序或批处理文件。这是什么原因?
我也有这个,难道是命令不一致吗
用双引号,curl "http://localhost:9999/login" -X POST -d "username=geektutu&password=1234"
用双引号完美解决,赞!!!
很棒的教程~
@Leoooo-tqp 感谢教程!我在使用curl命令 curl "http://localhost:9999/login" -X POST -d 'username=geektutu&password=1234' 时无法解析出传递的参数,并且显示'password' 不是内部或外部命令,也不是可运行的程序或批处理文件。这是什么原因?
改成双引号即可
讲的太好了
@codevvvv9
@walkmiao
@geektutu
@walkmiao 正确的调用顺序应该是Header().Set 然后WriteHeader() 最后是Write()
感谢指出,在
WriteHeader()
后调用Header().Set
是不会生效的,已经更正~感谢分享的教程
这个调用顺序是说哪里啊
If WriteHeader
has not yet been called, Write
calls
WriteHeader(http.StatusOK)
before writing the data.
Superfluous WriteHeader
has no effect. That's mean if we want to set
status code except http.StatusOK, we should call WriteHeader
before Write
.
Changing the header map after a call to WriteHeader
(or Write
) has no effect
unless the modified headers are trailers. That's mean if we want to modify the response
header, we should call Writer.Header().Set(key, value)
before WriteHeader
.
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)
}
}
我发现gin中的*Context.JSON
方法会调用*Context.Render
方法,而此方法会最先调用WriteHeader
方法,在整个调用链最后才会设置Content-Type
func writeContentType(w http.ResponseWriter, value []string) {
header := w.Header()
if val := header["Content-Type"]; len(val) == 0 {
header["Content-Type"] = value
}
}
这是为什么呢?不应该是 Header().Set 然后WriteHeader() 最后是Write()吗?
明白了 gin中的c.Writer类型是gin.ResponseWriter, 实际类型是gin.responseWriter,不是http.ResponseWriter
@geektutu @xiaoxfan 非常感谢指出了这个问题,之前的实现没有注意到这个问题。看到这里的童鞋可以看看gin的实现,地址贴在这里render/json.go#L56
Req.FormValue(key) 获取不到post参数吗
66