nginx模块开发之handler函数

http handler是http模块中最重要的函数, 直接托管http请求.

和前文set不同, set是在nginx启动的时候读取配置的过程中被触发的, 而handler函数是在真实请求到那个路径上时被触发的.

也就是浏览器请求多少次, handler就触发多少次.

返回值

handler的返回类型是ngx_int_t, 因为一般的http handler定义好body后就能交给http filter函数了, 比如我们hello模块的ngx_http_output_filter, 而filter函数都是返回整形数的.比如error就是-1.

参数

handler参数只有一个, ngx_http_request_t *req, 这个简单的出奇, 不过我用过不少http服务器框架, 也就只有nodejs分了request, response两个参数.

req是一个巨大的结构体.

不过这样的后果就是response的信息都写在request这个结构体上, 比如头部信息就是request.headers_out中.

请求的头部在headers_in中.

我们可以清楚的看到各种请求信息, 比如user_agent:

(gdb) p *req->headers_in.user_agent
p *req->headers_in.user_agent
$3 = {hash = 3194399592611459, key = {len = 10, data = 0x6eaa37 "User-Agent"}, v
   data = 0x6eaa43 "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHT
lowcase_key = 0x6ebc69 "user-agentaccept-encodingaccept-languagecookie"}

在printheaders_in的时候我们还发现nginx已经通过useragent帮你分辨好了浏览器..还专门列出了msie6.. 当然还有很多重要的头部信息, 比如`ifmodified_since,chunked,cookie`等.

在req中也有全部的我们需要的信息, 有method但不是保存字符串, 使用数字代表的, 比如get就是2. 还有http_version, 比如http1.1就是1001.

但是想uri, requestline, methodname, 都是显示一个request, line, 并没有做解析, 直接是生肉GET /test HTTP/1.1\r\nHost

但拥有全部http请求信息的我们也完全可以写出所有http相关的模块了.

源代码中是如何触发handler的

第一次使用gdb调试的时候发现调试不了, 马上就想起来nginx是分master和worker进程的, 在调试的时候, 我们不仅需要关掉daemmon后台运行, 以及master进程, 仅仅使用一个worker进程进行调试.

方法是修改nginx配置文件conf/nginx.conf,

daemon off;
master_process off;

这样就可以用gdb调试了.

handler函数在src/http/ngx_http_core_module.c中被调用.可以看到我们的handler函数被当成request结构体的content_handler属性.

返回ngx_http_output_filter(req, &out)的时候, 一次完整的请求+返回就完成了.