1. Interaksi antara acara acara dan rangka kerja http
Selepas menerima baris permintaan http dan pengepala permintaan http, fungsi ngx_http_process_request akan dipanggil untuk mula memproses permintaan http. Oleh kerana permintaan http terdiri daripada 11 peringkat pemprosesan, dan setiap peringkat pemprosesan membenarkan berbilang modul http untuk campur tangan, jadi dalam fungsi ini, modul http pada setiap peringkat akan dijadualkan untuk melengkapkan permintaan bersama-sama.
//接收到http请求行与请求头后,http的处理流程,是第一个http处理请求的读事件回调 //这个函数执行后,将把读写事件的回调设置为ngx_http_request_handler。这样下次再有事件时 //将调用ngx_http_request_handler函数来处理,而不会再调用ngx_http_process_request了 static void ngx_http_process_request(ngx_http_request_t *r) { ngx_connection_t *c; c = r->connection; //因为已经接收完http请求行、请求头部了,准备调用各个http模块处理请求了。 //因此需要接收任何来自客户端的读事件,也就不存在接收http请求头部超时问题 if (c->read->timer_set) { ngx_del_timer(c->read); } //重新设置当前连接的读写事件回调 c->read->handler = ngx_http_request_handler; c->write->handler = ngx_http_request_handler; //设置http请求对象的读事件回调,这个回调不做任何的事情。 //那http请求对象的读事件回调,与上面的连接对应的读事件回调有什么关系呢? //当读事件发生后,连接对应的读事件回调ngx_http_request_handler会被调用, //在这个回调内会调用http请求对象的读事件回调ngx_http_block_reading,而这个回调是 //不会做任何事件的,因此相当于忽略了读事件。因为已经接收完了请求行请求头,现在要做的是调用各个http模块, //对接收到的请求行请求头进行处理 r->read_event_handler = ngx_http_block_reading; //调用各个http模块协同处理这个请求 ngx_http_handler(r); //处理子请求 ngx_http_run_posted_requests(c); }
Fungsi ngx_http_process_request hanya akan dipanggil sekali. Jika satu jadual tidak dapat mengendalikan kesemua 11 peringkat http, panggilan balik acara baca dan tulis yang sepadan dengan objek sambungan akan ditetapkan kepada ngx_http_request_handler. Acara baca objek permintaan ditetapkan kepada ngx_http_block_reading, dan panggilan balik acara tulis bagi objek permintaan ditetapkan kepada ngx_http_core_run_phases ini ditetapkan dalam ngx_http_handler. Dengan cara ini, fungsi
ngx_http_process_request tidak akan dipanggil apabila acara datang lagi. Apakah hubungan antara panggilan balik acara baca dan tulis modul acara acara dan panggilan balik acara baca dan tulis bagi objek permintaan http? dalam panggilan balik acara baca objek sambungan, panggilan balik acara baca objek permintaan http akan dipanggil. Panggilan balik acara tulis bagi objek sambungan akan memanggil panggil balik acara tulis bagi objek permintaan http.
Seperti yang dapat dilihat dalam rajah, apabila acara baca acara berlaku, panggilan balik ngx_http_request_handler acara baca akan dipanggil selepas pulangan epoll. Dalam panggilan balik acara baca ini, rangka kerja http akan dipanggil, iaitu panggilan balik acara baca ngx_http_block_reading objek permintaan http Panggil balik acara baca objek permintaan http ini tidak melakukan apa-apa, yang setara dengan mengabaikan acara baca. Oleh itu, bingkai http akan kembali ke modul acara. Jadi mengapa mengabaikan acara baca? Kerana semua baris permintaan http dan pengepala permintaan telah diterima. Apa yang perlu kita lakukan sekarang ialah menjadualkan pelbagai modul http untuk bekerja bersama-sama untuk menyelesaikan pemprosesan baris permintaan dan pengepala permintaan. Oleh itu tidak perlu menerima sebarang data daripada pelanggan.
, dan rangka kerja http akan dipanggil, iaitu panggilan balik acara tulis ngx_http_core_run_phases permintaan http objek. Panggilan balik rangka kerja http ini akan menjadualkan kaedah pengendali setiap modul http yang terlibat dalam 11 peringkat permintaan untuk melengkapkan permintaan http secara bersama.
2. Menjadualkan modul http untuk memproses permintaan
Dalam kod di atas, fungsi ngx_http_core_run_phases dijadualkan supaya setiap modul http boleh campur tangan dalam permintaan http. Fungsi ini ditetapkan dalam ngx_http_handler.
//http请求处理读与写事件的回调,在ngx_http_process_request函数中设置。 //这个函数中将会调用http请求对象的读写事件回调。将event事件模块与http框架关联起来 static void ngx_http_request_handler(ngx_event_t *ev) { //如果同时发生读写事件,则只有写事件才会触发。写事件优先级更高 if (ev->write) { r->write_event_handler(r); //在函数ngx_http_handler设置为:ngx_http_core_run_phases } else { r->read_event_handler(r); //在函数ngx_http_process_request设置为:ngx_http_block_reading } //处理子请求 ngx_http_run_posted_requests(c); }
Fungsi ngx_http_core_run_phases adalah sangat mudah Ia menjadualkan kaedah penyemak semua modul http yang terlibat dalam 11 peringkat pemprosesan http.
//调用各个http模块协同处理这个请求 void ngx_http_handler(ngx_http_request_t *r) { //不需要进行内部跳转。什么是内部跳转? 例如有个location结构,里面的 // if (!r->internal) { //将数组序号设为0,表示从数组第一个元素开始处理http请求 //这个下标很重要,决定了当前要处理的是11个阶段中的哪一个阶段, //以及由这个阶段的哪个http模块处理请求 r->phase_handler = 0; } else { //需要做内部跳转 cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module); //将序号设置为server_rewrite_index r->phase_handler = cmcf->phase_engine.server_rewrite_index; } //设置请求对象的写事件回调,这个回调将会调度介入11个http阶段的各个http模块 //共同完成对请求的处理 r->write_event_handler = ngx_http_core_run_phases; //开始调度介入11个http阶段的各个http模块 ngx_http_core_run_phases(r); }
Andaikan terdapat tiga modul http yang terlibat dalam permintaan http dalam fasa 2, satu modul terlibat dalam permintaan http dalam fasa 3, dan satu modul terlibat dalam permintaan dalam fasa 4. Apabila fasa 2 mula diproses, semua modul http dalam fasa 2 akan dipanggil untuk diproses Pada masa ini, phase_handler menunjuk ke kedudukan permulaan fasa 2. Selepas setiap modul dalam fasa 2 diproses, fasa_handler menunjuk ke modul seterusnya dalam fasa 2 sehingga pemprosesan fasa 2 selesai.
Apabila semua modul http dalam fasa 2 diproses, phase_handler akan menunjuk ke fasa 3
Kerana hanya terdapat satu modul http dalam fasa 3, apabila semua modul http dalam fasa 3 diproses, phase_handler akan menghala ke fasa 4
Apabila menghuraikan fail konfigurasi nginx.conf, apabila blok http dihuraikan, fungsi ngx_http_block akan dipanggil untuk mula menghuraikan blok http. Dalam fungsi ini, semua modul http yang perlu campur tangan dalam 11 peringkat permintaan http juga akan didaftarkan dalam tatasusunan.
//调用各个http模块协同处理这个请求, checker函数内部会修改phase_handler void ngx_http_core_run_phases(ngx_http_request_t *r) { cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module); ph = cmcf->phase_engine.handlers; //调用各个http模块的checker方法,使得各个http模块可以介入http请求 while (ph[r->phase_handler].checker) { rc = ph[r->phase_handler].checker(r, &ph[r->phase_handler]); //从http模块返回ngx_ok,http框架则会把控制全交还给事件模块 if (rc == ngx_ok) { return; } }
Contohnya, modul statik ngx_http_static_module akan menetapkan panggil balik fasa ngx_http_content_phase yang campur tangan dalam 11 fasa http kepada ngx_http_static_handler
//静态模块将自己注册到11个http请求阶段中的ngx_http_content_phase阶段 static ngx_int_t ngx_http_static_init(ngx_conf_t *cf) { cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module); h = ngx_array_push(&cmcf->phases[ngx_http_content_phase].handlers); //静态模块在ngx_http_content_phase阶段的处理方法 *h = ngx_http_static_handler; return ngx_ok; }
例如: ngx_http_access_module访问权限模块,会将自己介入11个http阶段的ngx_http_access_phase阶段回调设置为ngx_http_access_handler
//访问权限模块将自己注册到11个http请求阶段中的ngx_http_access_phase阶段 static ngx_int_t ngx_http_access_init(ngx_conf_t *cf) { cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module); h = ngx_array_push(&cmcf->phases[ngx_http_access_phase].handlers); //访问权限模块在ngx_http_access_phase阶段的处理方法 *h = ngx_http_access_handler; return ngx_ok; }
上面的这些操作,只是把需要介入到11个http阶段的http模块保存到了ngx_http_core_main_conf_t中的phases成员中,并没有保存到phase_engine中。那什么时候将phases的内容保存到phase_engine中呢? 还是在ngx_http_block函数中完成
//开始解析http块 static char * ngx_http_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { //初始化请求的各个阶段 if (ngx_http_init_phase_handlers(cf, cmcf) != ngx_ok) { return ngx_conf_error; } }
假设阶段1有一个http模块介入请求,阶段2有三个http模块介入请求、阶段3也有一个http模块介入请求。则ngx_http_init_phase_handlers这个函数调用后,从ngx_http_phase_t phases[11]数组转换到ngx_http_phase_handler_t handlers数组的过程如下图所示:
//初始化请求的各个阶段 static ngx_int_t ngx_http_init_phase_handlers(ngx_conf_t *cf, ngx_http_core_main_conf_t *cmcf) { //11个http请求阶段,每一个阶段都可以有多个http模块介入。 //这里统计11个节点一共有多个少http模块。以便下面开辟空间 for (i = 0; i < ngx_http_log_phase; i++) { n += cmcf->phases[i].handlers.nelts; } //开辟空间,存放介入11个处理阶段的所有http模块的回调 ph = ngx_pcalloc(cf->pool,n * sizeof(ngx_http_phase_handler_t) + sizeof(void *)); cmcf->phase_engine.handlers = ph; n = 0; //对于每一个http处理阶段,给该阶段中所有介入的http模块赋值 for (i = 0; i < ngx_http_log_phase; i++) { h = cmcf->phases[i].handlers.elts; switch (i) { case ngx_http_server_rewrite_phase://根据请求的uri查找location之前,修改请求的uri阶段 if (cmcf->phase_engine.server_rewrite_index == (ngx_uint_t) -1) { cmcf->phase_engine.server_rewrite_index = n; //重定向模块在数组中的位置 } checker = ngx_http_core_rewrite_phase; //每一个阶段的checker回调 break; case ngx_http_find_config_phase://根据请求的uri查找location阶段(只能由http框架实现) find_config_index = n; ph->checker = ngx_http_core_find_config_phase; n++; ph++; continue; case ngx_http_rewrite_phase: //根据请求的rui查找location之后,修改请求的uri阶段 if (cmcf->phase_engine.location_rewrite_index == (ngx_uint_t) -1) { cmcf->phase_engine.location_rewrite_index = n; } checker = ngx_http_core_rewrite_phase; break; case ngx_http_post_rewrite_phase: //ngx_http_rewrite_phase阶段修改rul后,防止递归修改uri导致死循环阶段 if (use_rewrite) { ph->checker = ngx_http_core_post_rewrite_phase; ph->next = find_config_index;//目的是为了地址重写后,跳转到ngx_http_find_config_phase阶段,根据 //url重写查找location n++; ph++; } continue; case ngx_http_access_phase: //是否允许访问服务器阶段 checker = ngx_http_core_access_phase; n++; break; case ngx_http_post_access_phase: //根据ngx_http_access_phase阶段的错误码,给客户端构造响应阶段 if (use_access) { ph->checker = ngx_http_core_post_access_phase; ph->next = n; ph++; } continue; case ngx_http_try_files_phase: //try_file阶段 if (cmcf->try_files) { ph->checker = ngx_http_core_try_files_phase; n++; ph++; } continue; case ngx_http_content_phase: //处理http请求内容阶段,大部分http模块最愿意介入的阶段 checker = ngx_http_core_content_phase; break; default: //ngx_http_post_read_phase, //ngx_http_preaccess_phase, //ngx_http_log_phase三个阶段的checker方法 checker = ngx_http_core_generic_phase; } n += cmcf->phases[i].handlers.nelts; //每一个阶段中所介入的所有http模块,同一个阶段中的所有http模块有唯一的checker回调, //但handler回调每一个模块自己实现 for (j = cmcf->phases[i].handlers.nelts - 1; j >=0; j--) { ph->checker = checker; ph->handler = h[j]; ph->next = n; ph++; } } return ngx_ok; }
四、http阶段的checker回调
在11个http处理阶段中,每一个阶段都有一个checker函数,当然有些阶段的checker函数是相同的。对每一个处理阶段,介入这个阶段的所有http模块都共用同一个checker函数。这些checker函数的作用是调度介入这个阶段的所有http模块的handler方法,或者切换到一下个http请求阶段。下面分析下ngx_http_post_read_phase,ngx_http_preaccess_phase,ngx_http_log_phase三个阶段的checker方法。
//ngx_http_post_read_phase, //ngx_http_preaccess_phase, //ngx_http_log_phase三个阶段的checker方法 //返回值: ngx_ok,http框架会将控制权交还给epoll模块 ngx_int_t ngx_http_core_generic_phase(ngx_http_request_t *r,ngx_http_phase_handler_t *ph) { ngx_int_t rc; //调用http模块的处理方法,这样这个http模块就介入到了这个请求阶段 rc = ph->handler(r); //跳转到下一个http阶段执行 if (rc == ngx_ok) { r->phase_handler = ph->next; return ngx_again; } //执行本阶段的下一个http模块 if (rc == ngx_declined) { r->phase_handler++; return ngx_again; } //表示刚执行的handler无法在这一次调度中处理完这一个阶段, //需要多次调度才能完成 if (rc == ngx_again || rc == ngx_done) { return ngx_ok; } //返回出错 /* rc == ngx_error || rc == ngx_http_... */ ngx_http_finalize_request(r, rc); return ngx_ok; }
Atas ialah kandungan terperinci Bagaimana nginx mengendalikan permintaan http. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!