Go从1.6升级至1.9/1.10后REST接口返回404问题排查求助
排查Go 1.6升级到1.9/1.10后REST接口返回404的问题
这个问题的根源其实是Go开发者常踩的一个基础坑——值传递与指针传递的区别,而Go版本的升级刚好把之前隐藏的bug彻底暴露了出来。
问题拆解
先看你的代码细节:
- 在
main.go里,http.NewServeMux()返回的是一个*http.ServeMux指针,这是Go标准库的设计规范——ServeMux本来就该以指针形式使用。 - 但你调用
handlers.TableHandler(*mux)时,把指针解引用成了值类型传递,而TableHandler的参数又是http.ServeMux值类型,这意味着函数内部操作的是原mux的副本,完全不是main函数里那个要用来处理请求的实例。
那为什么Go 1.6时能正常工作?这是个巧合:在Go 1.6及更早版本中,ServeMux内部的路由表是map类型(引用类型),值传递时副本的map和原实例的map指向同一个底层数据结构,所以在副本上注册路由,原实例碰巧能读到。但Go 1.7之后,官方对ServeMux的实现做了优化,值传递的副本修改不再影响原实例,这就导致你注册的路由根本没加到实际工作的mux上,自然所有请求都返回404。
修复方案
只需要修改两处代码,把ServeMux的传递改成指针类型:
- 调整
table_handler.go的函数参数
将参数从值类型改为指针类型:
func TableHandler(mux *http.ServeMux) { // 这里改为*http.ServeMux mux.HandleFunc("/gpdp/v1/prices/", func(w http.ResponseWriter, r *http.Request) { log.Println("request for prices: ", r.Method, r.Body) // 你的业务逻辑代码... }) }
- 修改
main.go的调用方式
直接传递mux指针,无需解引用:
import ( "net/http" ) func main() { mux := http.NewServeMux() handlers.TableHandler(mux) // 去掉前面的*,直接传指针 http.ListenAndServe(":8080", mux) // 别忘了启动服务,原代码可能省略了这行 }
额外提醒
http.ServeMux的设计初衷就是以指针形式使用,官方文档和所有示例都遵循这个规范。值传递属于未定义行为,不同版本可能有不同表现,以后写Go代码时要注意区分值类型与引用类型的传递逻辑,避免这类隐蔽的版本兼容问题。
内容的提问来源于stack exchange,提问作者Peter Scott Hayman
相关产品推荐
相关产品推荐

