nginx+lua學習——記一次靜態(tài)文件下載流程打點

nginx的 lua支持

一兰怠、nginx執(zhí)行步驟

nginx在處理每一個用戶請求時,都是按照若干個不同的階段依次處理的

  1. post-read
    讀取請求內(nèi)容階段你辣,nginx讀取并解析完請求頭之后就立即開始運行馅巷;

  2. server-rewrite
    server請求地址重寫階段;

  3. find-config
    配置查找階段格粪,用來完成當前請求與location配重塊之間的配對工作躏吊;

  4. rewrite
    location請求地址重寫階段,當ngx_rewrite指令用于location中帐萎,就是再這個階段運行的比伏;

  5. post-rewrite
    請求地址重寫提交階段,當nginx完成rewrite階段所要求的內(nèi)部跳轉(zhuǎn)動作疆导,如果rewrite階段有這個要求的話赁项;

  6. preaccess
    訪問權(quán)限檢查準備階段,ngx_limit_req和ngx_limit_zone在這個階段運行,ngx_limit_req可以控制請求的訪問頻率悠菜,ngx_limit_zone可以控制訪問的并發(fā)度舰攒;

  7. access
    權(quán)限檢查階段,ngx_access在這個階段運行悔醋,配置指令多是執(zhí)行訪問控制相關(guān)的任務摩窃,如檢查用戶的訪問權(quán)限,檢查用戶的來源IP是否合法篙顺;

  8. post-access
    訪問權(quán)限檢查提交階段偶芍;

  9. try-files
    配置項try_files處理階段;

  10. content
    內(nèi)容產(chǎn)生階段德玫,是所有請求處理階段中最為重要的階段匪蟀,因為這個階段的指令通常是用來生成HTTP響應內(nèi)容的;

  11. log
    日志模塊處理階段宰僧;

nginx_lua的常用模塊

在openwrt上我們一般利用nginx_lua的以下幾個功能

  1. set_by_lua:主要做一些參數(shù)配置時使用
  2. header_filter_by_lua:頭部請求信息的預處理
  3. access_by_lua_file:對應上面的第7階段材彪,我們可以在這里對業(yè)務請求信息做一些處理
  4. content_by_lua_file:對應上面的第10階段
  5. log_by_lua_file:對應上面的第11階段,在content_by_lua_file之后運行琴儿。

業(yè)務需求:本地文件下載打點(開始——結(jié)束)

  1. 需求分析:
    1. 路由器上放置一個靜態(tài)文件段化,記錄客戶端下載這個文件的下載開始和下載結(jié)束的過程。
    2. 靜態(tài)文件路由器端是放在location中登記的:
    3. 靜態(tài)文件的下載造成,由于http響應內(nèi)就是文件显熏,所以content_by_lua_file就不需要了。
    4. 下載請求的記錄晒屎,我們可以在content_by_lua_file中獲取喘蟆。
    5. 下載最終返回數(shù)據(jù)的記錄,我們可以在log_by_lua_file中獲取鼓鲁。
  2. nginx配置:
    location ~* .(apk)$ {
        root  /tmp/loadapp;
        add_header Content-Disposition attachment;
        access_by_lua_file /system/nginx/lua/access_apk.lua;
        log_by_lua_file /system/nginx/lua/log_apk.lua;
    }
  1. 遇到的大問題:如何解決斷點續(xù)傳的打點蕴轨。
    1. 斷點續(xù)傳的大致原理:
      1. 客戶端向服務端并行發(fā)送多個http請求,http請求header中骇吭,會有一個range參數(shù)橙弱,range中包含了需要的文件片
      2. 服務端根據(jù)range信息取得響應的片返回給客戶端;
      3. 客戶端最終整合所有的文件片為一個文件燥狰。
    2. 斷點續(xù)傳是多請求多響應的棘脐,且下載是否完成是客戶端確認的,因此斷點續(xù)傳下龙致,路由器是無法準確知曉下載完畢的荆残。因此,如果需要對單個文件下載過程打點净当,就必須禁止斷點續(xù)傳。

3. 如何針對單個文件禁止斷點續(xù)傳

  1. 我們得知nginx的服務端斷點續(xù)傳功能支持是在ngx_http_range_filter_module中的
static ngx_int_t
ngx_http_range_header_filter(ngx_http_request_t *r)
{
    time_t                        if_range;
    ngx_int_t                     rc;
    ngx_http_range_filter_ctx_t  *ctx;

    if (r->http_version < NGX_HTTP_VERSION_10
        || r->headers_out.status != NGX_HTTP_OK
        || r != r->main
        || r->headers_out.content_length_n == -1
        || !r->allow_ranges)
    {
        return ngx_http_next_header_filter(r);
    }
}
  1. 因此我們只需要在nginx收到http請求的時候,r->allow_ranges=0即可
  2. 于是我們在nginx_lua模塊的ngx_http_lua_req_method.c中像啼,封裝了set_ranges和get_ranges兩個模塊
static int
ngx_http_lua_ngx_req_set_ranges(lua_State * L)
{
    ngx_http_request_t               *r;
    int range = luaL_checkinteger(L, 1);
    r = ngx_http_lua_get_req(L);
    if (r == NULL) {
        return luaL_error(L, "no request object found");
    }
    r->allow_ranges = range;
    return 1;
}


static int
ngx_http_lua_ngx_req_get_ranges(lua_State *L)
{
    ngx_http_request_t      *r;
    r = ngx_http_lua_get_req(L);
    if (r == NULL) {
        return luaL_error(L, "request object not found");
    }
    lua_pushinteger(L, r->allow_ranges);
    return 1;
}
  1. 當收到http請求時俘闯,執(zhí)行set_ranges(0)
ngx.req.set_ranges(0)
  1. 我們在nginx端實現(xiàn)了對請求的range的攔截,但依然無法控制客戶端發(fā)出多個請求忽冻,因此nginx還是收到了多個http請求真朗。不過對nginx而言,這么多的請求中只有一個是返回給了具體的文件數(shù)據(jù)僧诚。因此我們只要找到這一對特殊的請求/響應即可遮婶。通過對tcpdump的分析,我們發(fā)現(xiàn)這個的請求的特征如下
local h1 = ngx.req.get_headers();
local range = h1["Range"];
local accept_encoding = h1["Accept_Encoding"];
if range == nil and accept_encoding == "identity" then
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末湖笨,一起剝皮案震驚了整個濱河市旗扑,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌慈省,老刑警劉巖臀防,帶你破解...
    沈念sama閱讀 216,470評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異边败,居然都是意外死亡袱衷,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,393評論 3 392
  • 文/潘曉璐 我一進店門笑窜,熙熙樓的掌柜王于貴愁眉苦臉地迎上來致燥,“玉大人,你說我怎么就攤上這事排截∠釉椋” “怎么了?”我有些...
    開封第一講書人閱讀 162,577評論 0 353
  • 文/不壞的土叔 我叫張陵匾寝,是天一觀的道長搬葬。 經(jīng)常有香客問我,道長艳悔,這世上最難降的妖魔是什么急凰? 我笑而不...
    開封第一講書人閱讀 58,176評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮猜年,結(jié)果婚禮上抡锈,老公的妹妹穿的比我還像新娘。我一直安慰自己乔外,他們只是感情好床三,可當我...
    茶點故事閱讀 67,189評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著杨幼,像睡著了一般撇簿。 火紅的嫁衣襯著肌膚如雪聂渊。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,155評論 1 299
  • 那天四瘫,我揣著相機與錄音汉嗽,去河邊找鬼。 笑死找蜜,一個胖子當著我的面吹牛饼暑,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播洗做,決...
    沈念sama閱讀 40,041評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼弓叛,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了诚纸?” 一聲冷哼從身側(cè)響起撰筷,我...
    開封第一講書人閱讀 38,903評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎咬清,沒想到半個月后闭专,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,319評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡旧烧,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,539評論 2 332
  • 正文 我和宋清朗相戀三年影钉,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片掘剪。...
    茶點故事閱讀 39,703評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡平委,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出夺谁,到底是詐尸還是另有隱情廉赔,我是刑警寧澤,帶...
    沈念sama閱讀 35,417評論 5 343
  • 正文 年R本政府宣布匾鸥,位于F島的核電站蜡塌,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏勿负。R本人自食惡果不足惜馏艾,卻給世界環(huán)境...
    茶點故事閱讀 41,013評論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望奴愉。 院中可真熱鬧琅摩,春花似錦、人聲如沸锭硼。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,664評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽檀头。三九已至轰异,卻和暖如春岖沛,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背溉浙。 一陣腳步聲響...
    開封第一講書人閱讀 32,818評論 1 269
  • 我被黑心中介騙來泰國打工烫止, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人戳稽。 一個月前我還...
    沈念sama閱讀 47,711評論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像期升,于是被迫代替她去往敵國和親惊奇。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,601評論 2 353

推薦閱讀更多精彩內(nèi)容