Nginx中如果需要處理請求體,之后交由其他模塊處理,常用的方式有三種:
- 用一個content除非的handle模塊接收處理請求體,處理完成后內部跳轉給其他location。比如nginx-upload-module就是采用這種方法。
- 注冊一個rewrite階段的handle模塊接收處理請求體。之后按原nginx模塊流程。比如form-input-nginx-module和ngx_json_post_module就是采用這模式
- 注冊一個nginx request body filter,使用類似response body filter的方式進行處理。
當然這三種方法的適用場景并不相同。這里主要介紹方法3,適用于流式處理請求body數據。
首先,可以用類似注冊response filter的方式在模塊的postconfigure方法中注冊request body filter
static ngx_http_request_body_filter_pt ngx_http_next_request_body_filter;
static ngx_int_t ngx_http_example_post_conf(ngx_conf_t *cf)
{
// register input filter
ngx_http_next_request_body_filter = ngx_http_top_request_body_filter;
ngx_http_top_request_body_filter = ngx_http_example_request_body_filter;
return NGX_OK;
}
之后像編寫response body filter一樣完成request body filter方法就可以了。當然,這里需要注意的是,如果經過這個filter處理之后改變了原本請求的body的長度,記得一定要在最后修正頭部的content length,以免讓之后的模塊或upstream拿到錯誤的content length。
static ngx_int_t
ngx_http_example_request_body_filter(ngx_http_request_t *r, ngx_chain_t *in)
{
// ...
if (last_buf_in_this_filter) {
r->headers_in.content_length_n = cry->total_len;
r->headers_in.content_length->value.data = ngx_palloc(r->pool, NGX_OFF_T_LEN);
if (r->headers_in.content_length->value.data == NULL) {
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
r->headers_in.content_length->value.len =
ngx_sprintf(r->headers_in.content_length->value.data, "%O", r->headers_in.content_length_n)
- r->headers_in.content_length->value.data;
}
return ngx_http_next_request_body_filter(r, in);
}
而正常情況(在沒有第三模塊注冊request body filter時),該request body filter的執(zhí)行順序是在ngx_http_request_body_length_filter或ngx_http_request_body_chunked_filter之后執(zhí)行,在這里處理數據不用擔心chunked編碼的問題,而對應的ngx_http_next_request_body_filter(也就是注冊模塊前的ngx_http_top_request_body_filter)正好是ngx_http_request_body_save_filter。當然,要注意的,request body filter只有在真正接收請求body時才會被執(zhí)行,比如在handle里請求接收數據,或者向后端upstream轉發(fā)請求body時。
作者原創(chuàng),轉載請注明出處