Nginx做代理的一次實踐
阿新 • • 發佈:2019-02-03
背景
所在專案Go服務之前部署在測試機器上,最近再把Go的配置遷移到etcd,但是因為etcd沒有對應的測試環境,而公司裡面網段是隔離的,導致了原本的Go服務再接入etcd之後跑不起來。
- 讓Go服務正常啟動,
- 其他依賴方,比如前端、閘道器少做修改
方案
Go服務部署到docker上,docker上的域名都是特定字尾結尾,這樣會涉及到cookie等一些問題,所以考慮通過測試機的Nginx做代理。
問題
- http 426 報錯:測試環境的http協議是1.0,而docker上的http協議是1.1,所以需要在nginx轉發的時候,新增header頭。如果是websocket可以參考下
- http 404 報錯:Nginx在做轉發的時候,需要加上host header頭,域名解析找到對應的主機,但是需要根據host資訊,找到對應的服務。
插曲
再解決問題的時候,通過curl -I 在訪問docker上的服務,一直提示404,但是通過curl直接訪問的時候,正常。後來想到curl -I是通過head的方式請求。專案註冊的路由請求方式是get,但是Iris的底層路由,404和405報錯不能共存,iris預設會將404和405報錯統一的轉換成404報錯。
直接上程式碼
pool.Run(w, r, func (context *iris.Context) {
routePath := context.Path()
for i := range mux.garden {
tree := mux.garden[i]
if !mux.methodEqual(context.Request.Method, tree.method) {
continue
}
if mux.hosts && tree.subdomain != "" {
requestHost := context.Host()
// println("mux are true and tree.subdomain= " + tree.subdomain + "and hostname = " + hostname + " host = " + requestHost)
if requestHost != hostname {
// we have a subdomain
if strings.Contains(tree.subdomain, iris.DynamicSubdomainIndicator) {
} else {
if tree.subdomain+hostname != requestHost {
// go to the next tree, we have a subdomain but it is not the correct
continue
}
}
} else {
//("it's subdomain but the request is not the same as the vhost)
continue
}
}
mustRedirect := tree.entry.getValue(routePath, context) // pass the parameters here for 0 allocation
if context.Middleware != nil {
// ok we found the correct route, serve it and exit entirely from here
//ctx.Request.Header.SetUserAgentBytes(DefaultUserAgent)
context.Do()
return
} else if mustRedirect && !context.Framework().Config.DisablePathCorrection { // && context.Method() == MethodConnect {
reqPath := routePath
pathLen := len(reqPath)
if pathLen > 1 {
if reqPath[pathLen-1] == '/' {
reqPath = reqPath[:pathLen-1] //remove the last /
} else {
//it has path prefix, it doesn't ends with / and it hasn't be found, then just add the slash
reqPath = reqPath + "/"
}
urlToRedirect := reqPath
statusForRedirect := iris.StatusMovedPermanently // StatusMovedPermanently, this document is obselte, clients caches this.
if tree.method == iris.MethodPost ||
tree.method == iris.MethodPut ||
tree.method == iris.MethodDelete {
statusForRedirect = iris.StatusTemporaryRedirect // To maintain POST data
}
context.Redirect(urlToRedirect, statusForRedirect)
// RFC2616 recommends that a short note "SHOULD" be included in the
// response because older user agents may not understand 301/307.
// Shouldn't send the response for POST or HEAD; that leaves GET.
if tree.method == iris.MethodGet {
note := "<a href=\"" + HTMLEscape(urlToRedirect) + "\">Moved Permanently</a>.\n"
// ignore error
context.WriteString(note)
}
return
}
}
// not found
break
}
// https://github.com/kataras/iris/issues/469
if context.Framework().Config.FireMethodNotAllowed {
var methodAllowed string
for i := range mux.garden {
tree := mux.garden[i]
methodAllowed = tree.method // keep track of the allowed method of the last checked tree
if !mux.methodEqual(context.Method(), tree.method) {
continue
}
}
// RCF rfc2616 https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
// The response MUST include an Allow header containing a list of valid methods for the requested resource.
context.SetHeader("Allow", methodAllowed)
context.EmitError(iris.StatusMethodNotAllowed)
return
}
context.EmitError(iris.StatusNotFound)
})