nginx的腳本引擎(一)

nginx的腳本的語法和shell是很像的,我大致看了一下覺得挺有意思的,就想寫寫記錄一下。我沒看過shell腳本的引擎,不知道nginx腳本引擎和shell腳本引擎像不像,但是我覺得nginx的腳本引擎有點像C和匯編。

ngx_http_script_engine_t這個結構就代表了一段腳本,ip指向的是編譯好的腳本,sp指向的是一塊內存用來存儲腳本運行的時候產生的一些中間值。ip/sp從名字看就已經很像匯編了instruction pointer/stack pointer指令寄存器和棧寄存器呀,當然是我瞎猜的,有時間的話可以查一下官方文檔。代碼段里的各個指令長度不一定相同。

再來說說編譯過程,編譯過程是在nginx_http_script_engine_t建立之前執行的,我先畫出了整個圖是為了更好理解。舉個set指令編譯的的例子,比如你在腳本里有這樣的代碼set $foo helloworld,腳本編譯的步驟如下:

第一步:首先在cmcf->variables_keys和cmcf->variables里增加一個變量foo,這個變量是可寫的。我之前寫的nginx的變量系統里只說了變量的讀取方法,差別不大。

第二步:把ngx_http_script_value_code_t指令放到代碼段里(code字段是一個回調函數,賦值成ngx_http_script_value_code),把ngx_http_script_var_code_t指令放到代碼段里(code字段是一個回調函數,賦值成ngx_http_script_set_var_code)。

第三步:http請求來的時候會在rewrite階段按順序執行ip指向的這一段代碼,也就是執行ngx_http_script_value_code和ngx_http_script_set_var_code函數。

我們看一下這兩個函數做了什么

void
ngx_http_script_value_code(ngx_http_script_engine_t *e)
{ngx_http_script_value_code_t  *code;code = (ngx_http_script_value_code_t *) e->ip;e->ip += sizeof(ngx_http_script_value_code_t);e->sp->len = code->text_len;e->sp->data = (u_char *) code->text_data;ngx_log_debug1(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0,"http script value: \"%v\"", e->sp);e->sp++;
}
void
ngx_http_script_set_var_code(ngx_http_script_engine_t *e)
{ngx_http_request_t          *r;ngx_http_script_var_code_t  *code;code = (ngx_http_script_var_code_t *) e->ip;e->ip += sizeof(ngx_http_script_var_code_t);r = e->request;e->sp--;r->variables[code->index].len = e->sp->len;r->variables[code->index].valid = 1;r->variables[code->index].no_cacheable = 0;r->variables[code->index].not_found = 0;r->variables[code->index].data = e->sp->data;
}

第一條指令把“helloworld”這個字符串放到了sp里,第二條指令把值從sp里取出來存到了變量系統的foo變量里,任務完成,看起來很簡單。

set指令還可以這樣用set $foo $x$y,這就是所謂的變量插值,過程和上面這個類似,只不過第一條指令是先從變量系統里取出$x和$y的值,再放入sp里。

其他指令和set指令的執行過程類似,把我看到的也寫一下吧

if指令:同樣舉個最簡單的例子if( $host = "www.foo.com" ),編譯的時候依次把ngx_http_script_var_code/ngx_http_script_value_code_t/ngx_http_script_equal_code/ngx_http_script_if_code四條指令放到代碼段里。腳本運行的時候這幾條指令的工作分別是ngx_http_script_var_code把變量host的值取出來放到sp里。ngx_http_script_value_code_t把字符串“www.foo.com”放到sp里。ngx_http_script_equal_code比較sp里存的兩個值是否相等并把兩個值清除掉,相等就在sp里寫入“1”,不相等就寫入“0”(比較完以后這兩個值就沒用了,清除掉這兩個值并且寫入結果很像C里函數調用的過程)。ngx_http_script_if_code檢查sp里的值是不是“0”,不是“0”說明條件為真繼續執行之后的腳本,是“0”說明條件為假就會跳過這一段代碼執行ngx_http_script_if_code_t結構里next偏移之后的代碼。所有的代碼都是在一個代碼段里,不會因為有if把代碼做嵌套,只不過會用next跳來跳去。

有一點需要注意如果if在location里if體里可以做一些location的配置,比如root之類的。當NGX_HTTP_REWRITE_PHASE階段執行腳本的時候會把新的loc_conf賦值給r->loc_conf,這個一定要注意是NGX_HTTP_REWRITE_PHASE階段而不是NGX_HTTP_FIND_CONFIG_PHASE階段,設置loc_conf一般情況是在NGX_HTTP_FIND_CONFIG_PHASE階段,但是這次不是。

void
ngx_http_script_if_code(ngx_http_script_engine_t *e)
{ngx_http_script_if_code_t  *code;code = (ngx_http_script_if_code_t *) e->ip;ngx_log_debug0(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0,"http script if");e->sp--;if (e->sp->len && (e->sp->len != 1 || e->sp->data[0] != '0')) {if (code->loc_conf) {e->request->loc_conf = code->loc_conf;ngx_http_update_location_config(e->request);}e->ip += sizeof(ngx_http_script_if_code_t);return;}ngx_log_debug0(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0,"http script if: false");e->ip += code->next;
}

return指令:這個是比較簡單的,腳本執行到這個指令就直接返回了,參數了可以帶數據,例如return 200 helloworld,此外還可以重定向return 302 http://www.nginx.org。

break指令:粗暴的結束目前的腳本,但是有一點要注意,如果break指令在location里面,他并不會影響location其他字段的設置,因為他們在不同的階段執行。比如說設置如下的配置文件

        location / {root html;break;index index.html;}

?這一點都不會影響你的index指令,他們不在同一階段,index是在NGX_HTTP_FIND_CONFIG_PHASE階段break是在NGX_HTTP_REWRITE_PHASE階段,就像if指令里說的那樣。

rewrite指令:這個略顯麻煩,但是道理是一樣的,休息,明天接著寫。

轉載于:https://www.cnblogs.com/4a8a08f09d37b73795649038408b5f33/p/9985528.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/450630.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/450630.shtml
英文地址,請注明出處:http://en.pswp.cn/news/450630.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

一個待辦事列表todolist

最近有位老師讓我做的,圖片在下面,做了4個多小時,ui有的簡陋,可以再美化一下,這個會更好看,畢竟我也不是專業前端,測試網站http://todolist.sshouxin.top/使用的是thinkphp5.1的框架&#xff0c…

詳細說明 SourceTree 免登錄,跳過初始設置的方法(Windows 版 )

前些天發現了一個巨牛的人工智能學習網站,通俗易懂,風趣幽默,忍不住分享一下給大家。點擊跳轉到教程。 1. 首先,安裝完 SourceTree 以后先運行一次,彈出初始化登錄頁面后退出。 2. 進入這個文件夾:C:\Users…

什么是好的API設計?

摘要:有人言,API設計是編程工作中最難的事情。甚至有人認為至少要有10年的工作經驗才能接觸它。不過這里提出了一個引人思考的問題:究竟是構建什么樣的庫需要花費10年的時間去學習? 有人言,API設計是編程工作中最難的事…

Linux學習記錄-文件、目錄與磁盤

用戶和群組 用戶和群組主要是為了區分用戶對文件的操作權限。 賬號在/etc/passwd個人密碼在/etc/shadow組信息在/etc/group 不要亂動這3個文件文件權限和目錄配置 文件屬性 文件前綴解釋,例如: 第一個字符代表這個文件是『目錄、文件或鏈接文件等等』&am…

php curl模擬https請求

https請求(支持GET和POST) function http_request($url,$data null){$curl curl_init();curl_setopt($curl, CURLOPT_URL, $url);curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE);if(!empty($data)){curl_setopt($cur…

springboot集成環信sdk報錯

import io.swagger.client.ApiException; import io.swagger.client.api.MessagesApi; import io.swagger.client.model.Msg 這個是因為少兩個包,只需要把在你的pom.xml添加以下代碼即可,不要忘記點贊哈只需要添加兩個包即可,你可以自行網上下…

解決 error: Your local changes to the following files would be overwritten by merge:XXXX

前些天發現了一個巨牛的人工智能學習網站,通俗易懂,風趣幽默,忍不住分享一下給大家。點擊跳轉到教程。 idea 上將本地代碼推送到 git后 , 報錯如下圖 error: Your local changes to the following files would be overwritten by merge:src/…

深度有趣 | 30 快速圖像風格遷移

簡介 使用TensorFlow實現快速圖像風格遷移(Fast Neural Style Transfer) 原理 在之前介紹的圖像風格遷移中,我們根據內容圖片和風格圖片優化輸入圖片,使得內容損失函數和風格損失函數盡可能小 和DeepDream一樣,屬于網絡…

轉型從思維習慣的轉變開始

摘要:首先建議大家不要輕易轉向管理崗位,要認清自己是否適合做管理。轉型過程中應把握好幾點:良好的技術基礎,它是贏得團隊信任的前提,是把握團隊整體方向的關鍵;培養大局觀,只有站得高才能看得…

數據庫小知識點(一直更新)

一、mysql查詢是否含有某字段: mysql數據庫查詢帶有某個字段的所有表名 SELECT * FROM information_schema.columns WHERE column_namecolumn_name; oracle數據庫查詢帶有某個字段的所有表名 select column_name,table_name,from user_tab_columns where column_n…

其他運算符

原文地址:https://wangdoc.com/javascript/ void運算符 void運算符的作用是執行一個表達式,然后不返回任何值,或者說返回undefined。 void 0 // undefined void(0) // undefined 上面是void運算符的兩種寫法,都正確。建議采用后一…

git pull --rebase 做了什么? 以及 Cannot rebase: You have unstaged changes 解決辦法

前些天發現了一個巨牛的人工智能學習網站,通俗易懂,風趣幽默,忍不住分享一下給大家。點擊跳轉到教程。 最近剛學 git rebase,覺得很牛逼的樣子, 結果今天就被打臉了。 git pull --rebase 1 報錯: Cann…

vue如何實現單頁緩存方案分析

實現全站的頁面緩存,前進刷新,返回走緩存,并且能記住上一頁的滾動位置,參考了很多技術實現,github上的導航組件實現的原理要么使用的keep-alive,要么參考了keep-alive的源碼,但是只用keep-alive…

C語言常用函數簡介

一、字符測試函數 isupper()測試字符是否為大寫英文字ispunct()測試字符是否為標點符號或特殊符號isspace()測試字符是否為空格字符isprint()測試字符是否為可打印字符islower()測試字符是否為小寫字母isgraphis()測試字符是否為可打印字符isdigit()測試字符是否為阿拉伯數字i…

thinkphp如何增加session的過期時間

原理:我們都知道session是建立在cookie的基礎上的,如果瀏覽器cookie清楚了,則tp就會重新建立一個session。 操作:直接增加瀏覽器的cookie的到期時間,就可以使tp的session增加。

需求心得

電路圖是人們為研究、工程規劃的需要。我們組項目需要設計實現一個矢量圖編輯器。在通過對變電站的電路圖進行矢量繪圖后,就可以通過矢量圖的縮放詳細信息。在分析需求后,寫下心得! 分析需求主要有一下幾個步驟: 1. 獲取和引導需求…

IT部門不應該是一個后勤部門

管理上最大的問題在于不重視預算與核算的管理。從管理層到員工,很少有經營的念頭,只是一味地埋頭做事。西方企業總結了當今幾百年的經營理念,最終把企業一切活動的評價都歸結到唯一的、可度量的標準上:錢來度量。 by——華為 作為…

you need to resolve your current index first 解決辦法

前些天發現了一個巨牛的人工智能學習網站,通俗易懂,風趣幽默,忍不住分享一下給大家。點擊跳轉到教程。 從一個分支A切換到另一個分支B后,對切換后的B分支進行pull操作,因為pull操作實際上包含了fetchmerge操作&#x…

C語言,一種如此美麗的語言

人們說足球是一種優美的體育運動,而當我們在綠茵場上看到羅納爾多那行云流水的帶球動作時,我們不能不承認這種說法。然而,對于我來說,這種運動之所以如此的賞心悅目,跟那些乖張的天才球星們關系并不是那么大&#xff0…

基于websocket的聊天實現邏輯(springboot)

websocket的知識點:當用戶建立socket連接請求之后,服務器會給客戶段建一個session(非httpsession),這是是對客戶端的唯一識別碼,用于消息通信 第二上流程圖,流程圖解釋:用戶1要給用戶2發送消息…