nginx的指令碼引擎(二)rewrite
其實rewrite指令和上一篇說的if/set/return/break之類的沒多大差別,但是rewrite用起來相對複雜,我就把他單獨放到了這裡。想要弄懂nginx的指令碼引擎需要先明白處理request的十一個處理階段,不懂的話先去搜一下看看,網上很多。先說一下rewrite的用法吧。
rewrite regex replacement [flag];
regex:用來匹配uri的正則表示式。
replacement:匹配成功後用這個欄位替換請求的uri。
上面這兩個沒什麼可說的,簡單明白,看一下flag,flag可以取的值如下:
last:當前指令執行完之後不在執行之後的指令,如果是在location塊裡這個請求會重新回到NGX_HTTP_FIND_CONFIG_PHASE階段用新的uri尋找新location。
break:當前指令執行完之後不在執行之後的指令。
redirect:返回302重定向。
permanent 返回301重定向。
redirect和permanent比較簡單,就不用說了,主要是區分last和break,這兩個指令用在server塊裡沒什麼區別,但是用在location塊裡就要注意了,下面這個配置是我把官方文件上的例子拿過來改的。
location /download/ { rewrite ^(/download/)(.*)\..*$ $1/mp3/$2.mp3 break; rewrite ^(/download/)(.*)\..*$ $1/mp3/$2.ra break; return 403; }
如果把break換成last,並且匹配上了這條指令修改uri之後,請求會重新回到NGX_HTTP_FIND_CONFIG_PHASE階段,因為uri的字首沒變會繼續匹配到這個location,再執行rewrite,造成死迴圈,最終返回500錯誤。
我覺得官方文件上的例子並不會造成500錯誤,是我理解的不對還是他舉的例子不對?傳送門http://nginx.org/en/docs/http/ngx_http_rewrite_module.html#rewrite
這幾個標誌都會執行如下的程式碼,結束當前的指令碼。
if (last) { code = ngx_http_script_add_code(lcf->codes, sizeof(uintptr_t), ®ex); if (code == NULL) { return NGX_CONF_ERROR; } *code = NULL; }
不同的是break的情況,break會額外執行如下的程式碼
if (code->uri) { r->internal = 1; r->valid_unparsed_uri = 0; if (code->break_cycle) { r->valid_location = 0; r->uri_changed = 0; } else { r->uri_changed = 1; } }
把r->uri_changed置位,到了NGX_HTTP_POST_REWRITE_PHASE會檢查這個標誌,如果不為0就會跳回NGX_HTTP_FIND_CONFIG_PHASE階段,這就是break標誌和last標誌的不同。