最新消息:

nginx proxy 模块请求发往上游

nginx admin 3211浏览 0评论

概述

nginx通过proxy_pass url; 来指定一组上游服务器,来实现7层http的反向代理功能。
通过URL指定一组上游服务器,URL可以是变量、域名、upstream的配置名称。

server {
    ......

    set $ups "127.0.0.1:8990";
    location /test1/ {
        proxy_pass http://$ups/;
    }

    location /test2/ {
        proxy_pass http://$ups;
    }

    location /test3/ {
        proxy_pass http://127.0.0.1:8991/;
    }

    location /test4/ {
        proxy_pass http://127.0.0.1:8991;
    }

    location /test5/ {
        proxy_pass http://127.0.0.1:8991/www/;
    }
}

 

对照上述4种配置的测试结果:

# curl -v 'http://127.0.0.1:8080/test1/hello/liwq'
$nc -l 127.0.0.1 8990
GET / HTTP/1.0

# curl -v 'http://127.0.0.1:8080/test2/hello/liwq'
$nc -l 127.0.0.1 8990
GET /test2/hello/liwq HTTP/1.0

#curl -v 'http://127.0.0.1:8080/test3/hello/liwq'
$nc -l 127.0.0.1 8991
GET /hello/liwq HTTP/1.0

#curl -v 'http://127.0.0.1:8080/test4/hello/liwq'
$nc -l 127.0.0.1 8991
GET /test4/hello/liwq HTTP/1.0

#curl -v 'http://127.0.0.1:8080/test5/hello/liwq'
$nc -l 127.0.0.1 8991
GET /www/hello/liwq HTTP/1.0

 

小结:
根据proxy_pass后的URL中是否有变量和是否有uri,转到上游的url不同:

  1. 有变量有uri:转到上游的请求url是proxy_pass 的URL中的uri。
  2. 有变量无uri:转到上游的请求url是原来请求的url。
  3. 无变量有uri:转到上游的请求url是proxy_pass 的URL中的uri + 原来请求去掉location 的name剩下的url。
  4. 无变量无uri:转到上游的请求url是原来请求的url。

代码解析

配置解析

下面通过解析proxy模块的proxy_pass指令来看看,proxy模块是如何选择上游服务器的,又是如何拼接请求把请求发往上游服务器的。下面介绍proxy_pass指令对应的代码ngx_http_proxy_pass函数。

  • 通过检测plcf->upstream.upstream || plcf->proxy_lengths 来判断是否在一个location重复配置proxy_pass指令。
  • 赋值该location下content阶段的处理函数为ngx_http_proxy_handler。
  • 判断URL是否有变量:
    • 有变量则调用ngx_http_script_compile函数把变量的回调函数添加到plcf->proxy_lengths和plcf->proxy_values数组中。
    • 没有变量,则调用ngx_http_upstream_add查找一组上游配置。

通过配置指令proxy_set_header设置一组发到上游的header,nginx代码是通过ngx_conf_set_keyval_slot函数把key val插入到plcf->headers_source数组中,数组的元素是ngx_keyval_t。
在merge_loc_conf 回调函数中,通过调用ngx_http_proxy_init_headers函数初始header。

ngx_http_proxy_init_headers 函数解析:

  • 分配了bucket,说明已经初始化完成了,不用再次初始化了。
  • 初始化headers_names为hash表,headers_merged为header 的key val结构。
  • 合并headers_source和default_headers到headers_merged数组中,两个数组中有相同的元素,取headers_source。
  • 遍历合并后的headers_merged数组,初始化hash表初始化所用的headers_names 数组。同时把合并数组中的header的长度以及回调函数存到headers->lengths数组中,内容存以及回调函数存到headers->values数组中,因涉及到变量,所以比较复杂。lengths数组中的元素是ngx_http_script_copy_code_t结构体,values数组中的元素是ngx_http_script_copy_code_t结构体,和该结构体后边紧跟的内容。如果header的val没有变量,则一个数组元素对应一个header,否则多个数组元素才对应一个header,两个header在数组中会用null隔开。val中变量会调用ngx_http_script_compile函数编译。
  • 编译headers->hash。

请求解析

下游请求到达时,解析完请求头后调用11个阶段,当调用到content阶段的时候执行ngx_http_proxy_handler回调函数。

  • 调用ngx_http_upstream_create函数创建一个upstream的结构体,赋值给r->upstream;
  • 创建proxy模块的请求上下文,其类型为ngx_http_proxy_ctx_t结构体。
  • 判断plcf->proxy_lengths数组是否为null
    • 如果为null,则说明proxy_pass的url没有变量。
    • 如果不为null,则说明url有变量,调用ngx_http_proxy_eval。
  • 赋值upstream结构体回调函数和变量。
  • 调用ngx_http_read_client_request_body函数读取完body后,再调用ngx_http_upstream_init函数初始化上游链接。

全部读取完下游请求后调用ngx_http_upstream_init初始化上游链接,实际上是调用的ngx_http_upstream_init_request函数。

  • 如果不保存上游结果且不忽略客户端异常且post_action为空,则赋值request的读写回调:
      r->read_event_handler = ngx_http_upstream_rd_check_broken_connection;
      r->write_event_handler = ngx_http_upstream_wr_check_broken_connection;
  • 客户端请求有body,则赋值:u->request_bufs = r->request_body->bufs;
  • 调用u->create_request回调函数创建发送到上游的请求体。其回调函数为:ngx_http_proxy_create_request
    • 计算发往上游请求的长度(方法长度+http版本长度+回车换行长度+uri的长度+[配置的body的长度]+ 配置的请求头的长度+原请求请求头的长度),注意:如果没有配置proxy_set_body,且proxy_pass_request_body为on,发到上游的body是原请求的body,原请求的body在r->request_body->bufs中,已经赋值给u->request_bufs。
    • 分配请求长度的内存,用来构建发往上游的请求。
    • plcf->proxy_lengths && ctx->vars.uri.len proxy_pass的URL有变量也有uri。则发到上游的uri为URL配置的uri。
    • URL中没有配置uri,解析客户端的请求uri有效且不是子请求,则发到上游的uri为原客户端的uri。
    • 是有效的location且proxy_pass的URL有uri,则发往上游的请求uri是proxy_pass的URL的uri+原请求的uri减去location name前缀再拼上原请求的参数。否则,发往上游请求的url是原客户端的url。
    • 请求头中,val为空的key val会被丢弃。
    • 如果没有配置proxy_set_body,且proxy_pass_request_body为on,且原请求有body,则把body挂到组装好的请求的内存链后边。
    • u->request_bufs指向发往上游的请求头+请求体。
  • uscf->peer.init
  • 调用ngx_http_upstream_connect函数向上游发起链接请求

转载请注明:爱开源 » nginx proxy 模块请求发往上游

您必须 登录 才能发表评论!