1. 程式人生 > >Nginx做代理的一次實踐

Nginx做代理的一次實踐

背景

所在專案Go服務之前部署在測試機器上,最近再把Go的配置遷移到etcd,但是因為etcd沒有對應的測試環境,而公司裡面網段是隔離的,導致了原本的Go服務再接入etcd之後跑不起來。

  • 讓Go服務正常啟動,
  • 其他依賴方,比如前端、閘道器少做修改

方案

Go服務部署到docker上,docker上的域名都是特定字尾結尾,這樣會涉及到cookie等一些問題,所以考慮通過測試機的Nginx做代理。

問題

  • http 426 報錯:測試環境的http協議是1.0,而docker上的http協議是1.1,所以需要在nginx轉發的時候,新增header頭。如果是websocket可以參考下
    https://www.nginx.com/blog/websocket-nginx/
  • 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) })