成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

Nginx location 配置踩坑過程分享

alighters / 2076人閱讀

摘要:所以到目前為止,基本可以肯定是的上出了一些問題。問題解決因篇幅有限,為了直面本次問題的核心,我不再貼出完整的配置,我簡化此次問題的模型。

  

這是五個(gè)小時(shí)與一個(gè)字符的戰(zhàn)斗

是的,作為一個(gè)程序員,你往往發(fā)現(xiàn),有的時(shí)候你花費(fèi)了數(shù)小時(shí),數(shù)天,甚至數(shù)星期來查找問題,但最終可能只花費(fèi)了數(shù)秒,改動(dòng)了數(shù)行,甚至幾個(gè)字符就解決了問題。這次給大家分享一個(gè)困擾了我很久,我花了五個(gè)小時(shí)才查找出問題原因,最終只添加了一個(gè)字符解決了的問題。

問題描述

我們的業(yè)務(wù)系統(tǒng)比較復(fù)雜,但最終提供給用戶的訪問接口比較單一,都是使用 Nginx 來做一個(gè)代理轉(zhuǎn)發(fā),而這個(gè)代理轉(zhuǎn)發(fā),往往需要匹配很多種不同類型的 URL 轉(zhuǎn)給不同的服務(wù)。這就使得我們的 Nginx 配置文件變得很復(fù)雜,粗略估計(jì)了下,我們有近20個(gè) upstream,有近60個(gè) location 匹配。這些配置按照模塊分布在不同的文件中,雖然復(fù)雜,但是仍然在我們的努力下運(yùn)行的良好。直到有一天,有位同事給我反映說偶爾有些 URL 會(huì)出現(xiàn) 404 的問題。一開始沒太在意,因?yàn)樗舱f不準(zhǔn)是哪一種 URL 才遇到這個(gè)問題。

問題查找

后來,慢慢的查找,找到了一些規(guī)律,一開始只知道是 tomcat 那邊返回 404了,想到 Nginx 都代理給了 tomcat,一開始就懷疑是程序的問題,不會(huì)想到是 Nginx。

我開始查找代碼的問題,我在本地的開發(fā)環(huán)境,嘗試了很久,我使用 8080 端口訪問,不論如何都是正確的結(jié)果,可是生產(chǎn)環(huán)境就是不行。然后我就聽信了某坑友同事的理論,重啟解決 95% 的問題,重裝解決 100%的問題,我嘗試重啟了 tomcat 和 Nginx,依然不行,然后是重裝,你猜結(jié)果如何????? ------想啥呢?當(dāng)然也是不行!

后來就開始懷疑是生產(chǎn)環(huán)境和開發(fā)環(huán)境的差異,去服務(wù)器上訪問 8080 端口,仍然是可以的??墒且唤?jīng)過 Nginx 代理,就不行。這個(gè)時(shí)候才開始懷疑是 Nginx 出了什么問題。

Nginx 怎么會(huì)出問題呢,業(yè)務(wù)系統(tǒng)中 URL 模式 /helloworld/* ,這樣的 URL 我們都是統(tǒng)一處理的。怎么會(huì)出現(xiàn)一些行,一些不行呢。問題表現(xiàn)為 A URL (/helloworld/nn/hello/world)沒問題,而 B URL(/helloworld/ii/hello/world) 有問題。

所以到目前為止,基本可以肯定是 Nginx 的 location 上出了一些問題。

問題解決

因篇幅有限,為了直面本次問題的核心,我不再貼出完整的 Nginx 配置,我簡化此次問題的模型。請(qǐng)看如下 Nginx 配置,這是我們之前的會(huì)導(dǎo)致問題的錯(cuò)誤配置模型。

worker_processes  1;
error_log  logs/error.log;
events {
    worker_connections  1024;
}

http {
    include       mime.types;
    default_type  application/octet-stream;
    log_format  main  "$remote_addr - $request_time - $remote_user [$time_local] "$request" "
                      "$status $body_bytes_sent "$http_referer" "
                      ""$http_user_agent" "$http_x_forwarded_for"";

    access_log  logs/access.log main;

    sendfile        on;
    keepalive_timeout  65;

    gzip  on;

    server {
        listen       80;
        server_name  localhost;
        location / {
            root   html;
            index  index.html index.htm;
        }
        location = /helloworld {
                return 602;
        }
        location /helloworld {
                return 603;
        }

        ## 生產(chǎn)環(huán)境中如下兩個(gè) location 在另外一個(gè)文件中,通過 include 包含進(jìn)來
        location /ii {
                return 604;
        }
        location ~ /ii/[^/]+/[^/]+ {
                return 605;
        }
        ##

        location ~ ^/helloworld/(scripts|styles|images).* {
                return 606;
        }
    }
}

注意,這里有幾點(diǎn)需要說明一下,生產(chǎn)環(huán)境的 Nginx 服務(wù)器配置文件比這里要復(fù)雜很多,而且是按模塊分布在不同的文件中的。這里簡化模型后,使用 Http 響應(yīng)狀態(tài)碼 60x 來區(qū)分到底被哪個(gè) location 匹配到了。
我針對(duì)當(dāng)時(shí)的情況,做了大量嘗試,最終的簡化版本如下:

嘗試1:http://localhost/helloworld ==> 602 符合預(yù)期

嘗試2:http://localhost/helloworld/hello ==> 603 符合預(yù)期

嘗試3:http://localhost/ii ==> 604 符合預(yù)期

嘗試4:http://localhost/ii/oo ==> 604 符合預(yù)期

嘗試5:http://localhost/ii/pp/kk ==> 605 符合預(yù)期

嘗試6:http://localhost/ii/pp/kk/ll ==> 605 符合預(yù)期

嘗試7:http://localhost/helloworld/scripts/aaa.js ==> 606 符合預(yù)期

嘗試8:http://localhost/helloworld/ii/hello/world ==> 605 不符合預(yù)期,預(yù)期為【603】

  

上面這些嘗試支持讀者自行試驗(yàn),Nginx 配置文件是完整可用的,我本地 Nginx 的版本是1.6.2

問題就在這里:我這里是事后,把這些匹配 location 標(biāo)記成了不同的響應(yīng)碼,才方便查找問題。當(dāng)發(fā)現(xiàn)這個(gè)不符合預(yù)期后,我還是難以理解,為何我一個(gè)以 /helloworld 開頭的 URL 會(huì)被匹配到 605 這個(gè)以 /ii 開頭的 location 里面來。在當(dāng)時(shí)的生產(chǎn)環(huán)境中,以 /ii 的配置統(tǒng)一放在另外一個(gè)文件中,這里是很難直觀的察覺出來這個(gè) /ii 跟訪問的 URL 里面的 /ii 的關(guān)系。

我不得不重新編譯了 Nginx ,加上了調(diào)試參數(shù),修改配置項(xiàng),看調(diào)試日志了。

這里不再講如何給 Nginx 加調(diào)試的編譯參數(shù),可自行查看相關(guān)文檔。修改配置項(xiàng)很簡單,只需要在

error_log  logs/error.log;

后面加上 debug 就可以了。

打出詳細(xì)調(diào)試日志后,訪問

http://localhost/helloworld/ii/hello/world

我得到了這樣的一段日志(省略掉了前后無用的日志,只保留有意義的一段):

2015/02/02 15:38:48 [debug] 5801#0: *60 http request line: "GET /helloworld/ii/hello/world HTTP/1.1"
2015/02/02 15:38:48 [debug] 5801#0: *60 http uri: "/helloworld/ii/hello/world"
2015/02/02 15:38:48 [debug] 5801#0: *60 http args: ""
2015/02/02 15:38:48 [debug] 5801#0: *60 http exten: ""
2015/02/02 15:38:48 [debug] 5801#0: *60 http process request header line
2015/02/02 15:38:48 [debug] 5801#0: *60 http header: "User-Agent: curl/7.37.1"
2015/02/02 15:38:48 [debug] 5801#0: *60 http header: "Host: localhost"
2015/02/02 15:38:48 [debug] 5801#0: *60 http header: "Accept: */*"
2015/02/02 15:38:48 [debug] 5801#0: *60 http header done
2015/02/02 15:38:48 [debug] 5801#0: *60 event timer del: 4: 1422862788055
2015/02/02 15:38:48 [debug] 5801#0: *60 rewrite phase: 0
2015/02/02 15:38:48 [debug] 5801#0: *60 test location: "/"
2015/02/02 15:38:48 [debug] 5801#0: *60 test location: "ii"
2015/02/02 15:38:48 [debug] 5801#0: *60 test location: "helloworld"
2015/02/02 15:38:48 [debug] 5801#0: *60 test location: ~ "/ii/[^/]+/[^/]+"
2015/02/02 15:38:48 [debug] 5801#0: *60 using configuration "/ii/[^/]+/[^/]+"
2015/02/02 15:38:48 [debug] 5801#0: *60 http cl:-1 max:1048576
2015/02/02 15:38:48 [debug] 5801#0: *60 rewrite phase: 2
2015/02/02 15:38:48 [debug] 5801#0: *60 http finalize request: 605, "/helloworld/ii/hello/world?" a:1, c:1
2015/02/02 15:38:48 [debug] 5801#0: *60 http special response: 605, "/helloworld/ii/hello/world?"
2015/02/02 15:38:48 [debug] 5801#0: *60 http set discard body
2015/02/02 15:38:48 [debug] 5801#0: *60 posix_memalign: 00007FC3BB816000:4096 @16
2015/02/02 15:38:48 [debug] 5801#0: *60 HTTP/1.1 605
Server: nginx/1.6.2
Date: Mon, 02 Feb 2015 07:38:48 GMT
Content-Length: 0
Connection: keep-alive

可以看到,Nginx 測試了幾次 location 匹配,最終選擇了

~ "/ii/[^/]+/[^/]+"

這個(gè)作為最終的匹配項(xiàng)。到這里問題就完全展現(xiàn)出來了,我們本來的意思,是要以 /ii 開頭,后面有兩個(gè)或者更多的 / 分割的 URL 模型才匹配,但是這里的正則表達(dá)式匹配寫的不夠精準(zhǔn),導(dǎo)致了匹配錯(cuò)誤。正則表達(dá)式?jīng)]有限制必須從開頭匹配,所以才會(huì)匹配到 /helloworld/ii/hello/world 這樣的 URL 。

解決辦法就是在這個(gè)正則表達(dá)式前面加上 ^ 來強(qiáng)制 URL 必須以 /ii 開頭才能匹配.

/ii/[^/]+/[^/]+

變成

^/ii/[^/]+/[^/]+

至此,這個(gè)坑被填上了,消耗的是五個(gè)小時(shí)和一個(gè)字符。

相信很多人在寫 Nginx 的location 的時(shí)候都會(huì) location ~ /xxx 或者 location /iii 這樣簡單了事,但是我想說的是能盡量精確就盡量精確,否則出現(xiàn)問題的時(shí)候,非常難以查找。

  

有關(guān) Nginx 的 location 匹配規(guī)則,可以查看: http://nginx.org/en/docs/http/ngx_http_core_module.html

問題總結(jié)

這個(gè)問題看似簡單,卻也隱含了不少問題,值得我們深思。

計(jì)算機(jī)或者軟件出的問題往往是確定的,你發(fā)現(xiàn)他捉摸不定的時(shí)候,往往是沒有觀察到問題點(diǎn)

追蹤一個(gè)問題,如果有一個(gè)必現(xiàn)方式,一定要緊追不舍,這就是所謂線索

當(dāng)你實(shí)在是找不到問題所在的時(shí)候,要懷疑一下之前被自己排除掉的可能性

借助各個(gè)組件的詳細(xì)調(diào)試日志來查找問題,往往能得到意想不到的效果

程序員的價(jià)值不是用行數(shù),字?jǐn)?shù),提交數(shù)衡量的!

  

本文作者: 王振威
文章出自: Coding 官方技術(shù)博客
如需轉(zhuǎn)載,請(qǐng)注明作者與出處,謝謝

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/39125.html

相關(guān)文章

  • career-tips | 踩坑

    摘要:因?yàn)槭嵌噙M(jìn)程單線程同步模式,即一個(gè)子進(jìn)程同時(shí)最多處理一個(gè)請(qǐng)求,所以子進(jìn)程數(shù)等于最大并發(fā)數(shù)。 a little tips in my code career | 碼碼踩過的那些坑2015-2016 記一下這一年碼碼中我需要去了解的基礎(chǔ)知識(shí),有不對(duì)的歡迎大家指證出來:https://github.com/TIGERB/car... 關(guān)于設(shè)計(jì)模式 關(guān)于PHP 關(guān)于互聯(lián)網(wǎng)協(xié)議 設(shè)計(jì)模...

    kviccn 評(píng)論0 收藏0
  • 工作踩坑系列——https訪問遇到“已阻止載入混合活動(dòng)內(nèi)容”

    摘要:問題復(fù)現(xiàn)經(jīng)過一段時(shí)間的調(diào)研工作,終于將公司的環(huán)境改造成支持訪問模式,信心滿滿的打開公司測試環(huán)境主頁,。當(dāng)一個(gè)網(wǎng)頁出現(xiàn)這種情況時(shí),它被稱為混合內(nèi)容頁面。請(qǐng)求,默認(rèn)行為。 前言 最近在主導(dǎo)公司網(wǎng)站進(jìn)行全站Https改造工作,本文記錄在改造過程中遇到的一個(gè)由于后端302跳轉(zhuǎn)導(dǎo)致前端瀏覽器阻止訪問的問題,感覺這樣的問題有一定通用性,所以編輯成文,希望能給遇到類似問題的人們有所幫助。 問題復(fù)現(xiàn) ...

    Shisui 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

閱讀需要支付1元查看
<