最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

關(guān)于nginx proxy_set部分常見配置

 更新時間:2024年05月14日 10:40:56   作者:liwenchao1995  
這篇文章主要介紹了關(guān)于nginx proxy_set部分常見配置,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教

nginx proxy_set部分常見配置

proxy_set_header Host $host;
#用途:設(shè)置要發(fā)送到代理服務(wù)器的HTTP請求頭的Host字段。$host變量將被替換為客戶端請求中的實際主機名。
 
proxy_set_header Connection "";
# 用途:清空要發(fā)送到代理服務(wù)器的HTTP請求頭的Connection字段。這可以避免由于Connection字段的錯誤配置而導致的代理連接無法正常關(guān)閉的問題。
 
proxy_set_header User-Agent $http_user_agent;
#用途:設(shè)置要發(fā)送到代理服務(wù)器的HTTP請求頭的User-Agent字段。$http_user_agent變量將被替換為客戶端請求中的實際User-Agent字符串。
 
proxy_set_header Referer $http_referer;
#用途:設(shè)置要發(fā)送到代理服務(wù)器的HTTP請求頭的Referer字段。$http_referer變量將被替換為客戶端請求中的實際Referer字符串。
 
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
#用途:設(shè)置要發(fā)送到代理服務(wù)器的HTTP請求頭的X-Forwarded-For字段。該字段用于記錄原始客戶端的IP地址。$proxy_add_x_forwarded_for變量將會在原有X-Forwarded-For字段的基礎(chǔ)上添加一個新的IP地址。
 
proxy_set_header X-Real-IP $remote_addr;
#用途:設(shè)置要發(fā)送到代理服務(wù)器的HTTP請求頭的X-Real-IP字段。該字段用于記錄客戶端的真實IP地址。$remote_addr變量將被替換為客戶端的真實IP地址。
 
proxy_set_header Accept-Encoding "";
#用途:清空要發(fā)送到代理服務(wù)器的HTTP請求頭的Accept-Encoding字段。這可以避免由于Accept-Encoding字段的錯誤配置而導致的代理服務(wù)器無法正確解壓縮響應(yīng)的問題。

需要注意的是:

這些指令的具體配置可能會因?qū)嶋H情況而異,例如需要設(shè)置的請求頭字段等,需要根據(jù)實際需求進行配置

記錄Nginx proxy_set_header的坑

背景

一個項目,使用nginx進行代理回源,新版本提交給測試同學后反饋說,回源Host被修改成固定的origin_upstream了。

第一反應(yīng):不應(yīng)該啊,這個版本我沒改回源Host相關(guān)的內(nèi)容啊,是不是你環(huán)境問題?哈哈。但又一想,origin_upstream這個值莫名其妙,恰好是proxy_pass配置中url出現(xiàn)的,明顯是有問題。

首先看了下代碼提交記錄,lua代碼沒有修改回源Host,排除;在回源的location中,增加了兩行配置。然后就沒有其他改動了。難道是location中的配置導致的?

配置文件結(jié)構(gòu)如下:

http {
	...
	upstream origin_upstream {
		...
	}
	server {
		proxy_set_header Host $host;
		proxy_set_header Connection "";
		proxy_http_version 1.1;
		...
		location x {
			...
		}
		location y {
			...
		}
		
		location @origin{
			...
			# 如下兩行是新版新增的,此處不是重復,是根據(jù)配置設(shè)置源站長連接
			proxy_set_header Connection $switch;
			proxy_http_version 1.1;
			
			proxy_pass http://origin_upstream$request_uri;
			...
		}
	}
}

去掉location中上述新增的兩行配置后,就正常了!最終確認,是proxy_set_header Connection $switch;的問題。

解決辦法:

在location中再加上如下配置,即可解決:

proxy_set_header Host $host;

原理

為什么location中的Host不會繼承server塊中配置的呢?

看下nginx文檔,如果在當前級別中沒有配置,則繼承上級配置。

默認情況,Host和Connection 會被重定義。

Syntax: proxy_set_header field value;
Default:
proxy_set_header Host $proxy_host;
proxy_set_header Connection close;
Context: http, server, location
Allows redefining or appending fields to the request header passed to the proxied server. The value can contain text, variables, and their combinations. These directives are inherited from the previous configuration level if and only if there are no proxy_set_header directives defined on the current level. By default, only two fields are redefined:
proxy_set_header Host $proxy_host;
proxy_set_header Connection close;

到底什么情況下,Host和Connection 才會被覆蓋呢?

懷著疑問,去看proxy_set_header這個指令的實現(xiàn)。

    { ngx_string("proxy_set_header"),
      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2,
      ngx_conf_set_keyval_slot,
      NGX_HTTP_LOC_CONF_OFFSET,
      offsetof(ngx_http_proxy_loc_conf_t, headers_source),
      NULL },

通過ngx_conf_set_keyval_slot這函數(shù)設(shè)置了ngx_http_proxy_loc_conf_t結(jié)構(gòu)體重的headers_source字段。

從下面實現(xiàn)可以看出,這個字段是一個kv鍵值對的數(shù)組。

char *
ngx_conf_set_keyval_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
    char  *p = conf;

    ngx_str_t         *value;
    ngx_array_t      **a;
    ngx_keyval_t      *kv;
    ngx_conf_post_t   *post;

    a = (ngx_array_t **) (p + cmd->offset);

    if (*a == NULL) {
        *a = ngx_array_create(cf->pool, 4, sizeof(ngx_keyval_t));
        if (*a == NULL) {
            return NGX_CONF_ERROR;
        }
    }

    kv = ngx_array_push(*a);
    if (kv == NULL) {
        return NGX_CONF_ERROR;
    }

    value = cf->args->elts;

    kv->key = value[1];
    kv->value = value[2];

    if (cmd->post) {
        post = cmd->post;
        return post->post_handler(cf, post, kv);
    }

    return NGX_CONF_OK;
}

headers_source字段在什么地方使用呢?

一處是在在ngx_http_proxy_merge_loc_conf合并配置時,一處是在ngx_http_proxy_init_headers這個函數(shù)中。

繼續(xù)看,發(fā)現(xiàn),ngx_http_proxy_init_headers這個函數(shù)在ngx_http_proxy_merge_loc_conf有調(diào)用。

static char *
ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
{
    ngx_http_proxy_loc_conf_t *prev = parent;
    ngx_http_proxy_loc_conf_t *conf = child;
    ...
    
    if (conf->headers_source == NULL) {
        conf->headers = prev->headers;
#if (NGX_HTTP_CACHE)
        conf->headers_cache = prev->headers_cache;
#endif
		// 如果location中沒有proxy_set_header配置,就集成上級配置
        conf->headers_source = prev->headers_source;
    }
    //緊接著就是調(diào)用ngx_http_proxy_init_headers
    rc = ngx_http_proxy_init_headers(cf, conf, &conf->headers,
                                     ngx_http_proxy_headers);
    if (rc != NGX_OK) {
        return NGX_CONF_ERROR;
    }
    ...
   }

我們繼續(xù)看下ngx_http_proxy_init_headers的邏輯:

static ngx_int_t
ngx_http_proxy_init_headers(ngx_conf_t *cf, ngx_http_proxy_loc_conf_t *conf,
    ngx_http_proxy_headers_t *headers, ngx_keyval_t *default_headers)
{
    u_char                       *p;
    size_t                        size;
    uintptr_t                    *code;
    ngx_uint_t                    i;
    ngx_array_t                   headers_names, headers_merged;
    ngx_keyval_t                 *src, *s, *h;
    ngx_hash_key_t               *hk;
    ngx_hash_init_t               hash;
    ngx_http_script_compile_t     sc;
    ngx_http_script_copy_code_t  *copy;

    if (headers->hash.buckets) {
        return NGX_OK;
    }

    if (ngx_array_init(&headers_names, cf->temp_pool, 4, sizeof(ngx_hash_key_t))
        != NGX_OK)
    {
        return NGX_ERROR;
    }

    if (ngx_array_init(&headers_merged, cf->temp_pool, 4, sizeof(ngx_keyval_t))
        != NGX_OK)
    {
        return NGX_ERROR;
    }

    headers->lengths = ngx_array_create(cf->pool, 64, 1);
    if (headers->lengths == NULL) {
        return NGX_ERROR;
    }

    headers->values = ngx_array_create(cf->pool, 512, 1);
    if (headers->values == NULL) {
        return NGX_ERROR;
    }

    // location中有配置proxy_set_header,則將其放入到headers_merged中。
    if (conf->headers_source) {

        src = conf->headers_source->elts;
        for (i = 0; i < conf->headers_source->nelts; i++) {

            s = ngx_array_push(&headers_merged);
            if (s == NULL) {
                return NGX_ERROR;
            }

            *s = src[i];
        }
    }

    h = default_headers;
	
	// while語句對default_headers對了一次遍歷,如果headers_merged沒有相同的key值,則使用default_headers的覆蓋
	// default_headers是什么?我們下面來看
    while (h->key.len) {

        src = headers_merged.elts;
        for (i = 0; i < headers_merged.nelts; i++) {
            if (ngx_strcasecmp(h->key.data, src[i].key.data) == 0) {
                goto next;
            }
        }

        s = ngx_array_push(&headers_merged);
        if (s == NULL) {
            return NGX_ERROR;
        }

        *s = *h;

    next:

        h++;
    }

    // 下面流程是將headers_merged合并如到入?yún)eaders->hash中,即請求的信息中。
    src = headers_merged.elts;
    for (i = 0; i < headers_merged.nelts; i++) {

        hk = ngx_array_push(&headers_names);
        if (hk == NULL) {
            return NGX_ERROR;
        }

        hk->key = src[i].key;
        hk->key_hash = ngx_hash_key_lc(src[i].key.data, src[i].key.len);
        hk->value = (void *) 1;

        if (src[i].value.len == 0) {
            continue;
        }

        copy = ngx_array_push_n(headers->lengths,
                                sizeof(ngx_http_script_copy_code_t));
        if (copy == NULL) {
            return NGX_ERROR;
        }

        copy->code = (ngx_http_script_code_pt) (void *)
                                                 ngx_http_script_copy_len_code;
        copy->len = src[i].key.len;

        size = (sizeof(ngx_http_script_copy_code_t)
                + src[i].key.len + sizeof(uintptr_t) - 1)
               & ~(sizeof(uintptr_t) - 1);

        copy = ngx_array_push_n(headers->values, size);
        if (copy == NULL) {
            return NGX_ERROR;
        }

        copy->code = ngx_http_script_copy_code;
        copy->len = src[i].key.len;

        p = (u_char *) copy + sizeof(ngx_http_script_copy_code_t);
        ngx_memcpy(p, src[i].key.data, src[i].key.len);

        ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));

        sc.cf = cf;
        sc.source = &src[i].value;
        sc.flushes = &headers->flushes;
        sc.lengths = &headers->lengths;
        sc.values = &headers->values;

        if (ngx_http_script_compile(&sc) != NGX_OK) {
            return NGX_ERROR;
        }

        code = ngx_array_push_n(headers->lengths, sizeof(uintptr_t));
        if (code == NULL) {
            return NGX_ERROR;
        }

        *code = (uintptr_t) NULL;

        code = ngx_array_push_n(headers->values, sizeof(uintptr_t));
        if (code == NULL) {
            return NGX_ERROR;
        }

        *code = (uintptr_t) NULL;
    }

    code = ngx_array_push_n(headers->lengths, sizeof(uintptr_t));
    if (code == NULL) {
        return NGX_ERROR;
    }

    *code = (uintptr_t) NULL;


    hash.hash = &headers->hash;
    hash.key = ngx_hash_key_lc;
    hash.max_size = conf->headers_hash_max_size;
    hash.bucket_size = conf->headers_hash_bucket_size;
    hash.name = "proxy_headers_hash";
    hash.pool = cf->pool;
    hash.temp_pool = NULL;

    return ngx_hash_init(&hash, headers_names.elts, headers_names.nelts);
}

從上面可以看到,location中如果headers_source為空,會使用default_headers進行覆蓋。

入?yún)efault_headers其實是ngx_http_proxy_headers,定義如下:

static ngx_keyval_t  ngx_http_proxy_headers[] = {
    { ngx_string("Host"), ngx_string("$proxy_host") },
    { ngx_string("Connection"), ngx_string("close") },
    { ngx_string("Content-Length"), ngx_string("$proxy_internal_body_length") },
    { ngx_string("Transfer-Encoding"), ngx_string("$proxy_internal_chunked") },
    { ngx_string("TE"), ngx_string("") },
    { ngx_string("Keep-Alive"), ngx_string("") },
    { ngx_string("Expect"), ngx_string("") },
    { ngx_string("Upgrade"), ngx_string("") },
    { ngx_null_string, ngx_null_string }
};

我們看到Host對應(yīng)的默認值為$proxy_host。

$proxy_host怎么獲取的呢?查看代碼可知,是通過對proxy_pass配置的url進行解析得出的。

而我們的配置文件中,$proxy_host會被解析為origin_upstream。

proxy_pass http://origin_upstream$request_uri;

$proxy_host解析的相關(guān)代碼:

static ngx_http_variable_t  ngx_http_proxy_vars[] = {

    { ngx_string("proxy_host"), NULL, ngx_http_proxy_host_variable, 0,
      NGX_HTTP_VAR_CHANGEABLE|NGX_HTTP_VAR_NOCACHEABLE, 0 },
     ...
 }

//proxy_host就是ctx->vars.host_header
static ngx_int_t
ngx_http_proxy_host_variable(ngx_http_request_t *r,
    ngx_http_variable_value_t *v, uintptr_t data)
{
    ngx_http_proxy_ctx_t  *ctx;

    ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);

    if (ctx == NULL) {
        v->not_found = 1;
        return NGX_OK;
    }

    v->len = ctx->vars.host_header.len;
    v->valid = 1;
    v->no_cacheable = 0;
    v->not_found = 0;
    v->data = ctx->vars.host_header.data;

    return NGX_OK;
}

 //在proxy_pass指令解析函數(shù)中,解析url,得到host,然后通過ngx_http_proxy_set_vars將host設(shè)置給host_header
static char *
ngx_http_proxy_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{ 
    ngx_str_t                  *value, *url;
    ngx_url_t                   u;
    ...
    
    u.url.len = url->len - add;
    u.url.data = url->data + add;
    u.default_port = port;
    u.uri_part = 1;
    u.no_resolve = 1;
	
	// ngx_http_upstream_add中,會調(diào)用ngx_parse_url(cf->pool, u)對url進行解析。
    plcf->upstream.upstream = ngx_http_upstream_add(cf, &u, 0);
    if (plcf->upstream.upstream == NULL) {
        return NGX_CONF_ERROR;
    }

    plcf->vars.schema.len = add;
    plcf->vars.schema.data = url->data;
    plcf->vars.key_start = plcf->vars.schema;
	
	// 完成對host_header的設(shè)置
    ngx_http_proxy_set_vars(&u, &plcf->vars);
	...
}

static void
ngx_http_proxy_set_vars(ngx_url_t *u, ngx_http_proxy_vars_t *v)
{
    if (u->family != AF_UNIX) {

        if (u->no_port || u->port == u->default_port) {

            v->host_header = u->host;

            if (u->default_port == 80) {
                ngx_str_set(&v->port, "80");

            } else {
                ngx_str_set(&v->port, "443");
            }

        } else {
            v->host_header.len = u->host.len + 1 + u->port_text.len;
            v->host_header.data = u->host.data;
            v->port = u->port_text;
        }

        v->key_start.len += v->host_header.len;

    } else {
        ngx_str_set(&v->host_header, "localhost");
        ngx_str_null(&v->port);
        v->key_start.len += sizeof("unix:") - 1 + u->host.len + 1;
    }

    v->uri = u->uri;
}

到這里,其實已經(jīng)很清楚了:

舊版本中,location中沒有proxy_set_header這個指令,合并配置時headers_source會繼承server中設(shè)置的Host、Connecion頭,從而不會被default_headers給覆蓋。所以,回源Host正確。

新版本中,location中新增了Connecion頭的配置,但是沒有Host頭,headers_source不會繼承server中的配置,從而導致Host頭被默認頭覆蓋。

總結(jié)

以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • nginx+iis實現(xiàn)簡單的負載均衡

    nginx+iis實現(xiàn)簡單的負載均衡

    這篇文章主要為大家詳細介紹了nginx+iis實現(xiàn)一個簡單的負載均衡的方法,感興趣的小伙伴們可以參考一下
    2016-03-03
  • Nginx通過geo模塊設(shè)置白名單的例子

    Nginx通過geo模塊設(shè)置白名單的例子

    今天小編就為大家分享一篇Nginx通過geo模塊設(shè)置白名單的例子,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2019-08-08
  • Nginx 防止目錄遍歷的方法實現(xiàn)

    Nginx 防止目錄遍歷的方法實現(xiàn)

    目錄遍歷攻擊是一種常見的Web安全漏洞,本文主要介紹了Nginx防止目錄遍歷的方法實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2024-12-12
  • Nginx定時切割日志實現(xiàn)詳解

    Nginx定時切割日志實現(xiàn)詳解

    這篇文章主要介紹了Nginx定時切割日志詳解,Nginx日志默認情況下寫入到一個文件中,為了區(qū)分各個域下的日志,我們一般會分開存儲。即時這樣,文件也會變的越來越大,非常不方便查看分析。下面來聊聊以日期來分隔Nginx日志,需要的朋友可以參考下
    2019-07-07
  • 深入解析nginx路由location匹配規(guī)則及其優(yōu)先級

    深入解析nginx路由location匹配規(guī)則及其優(yōu)先級

    Nginx是一款高性能的Web服務(wù)器和反向代理服務(wù)器,它的路由功能是通過location指令來實現(xiàn)的,location指令用于匹配請求的URL,并將請求轉(zhuǎn)發(fā)到相應(yīng)的處理程序或靜態(tài)文件,需要的朋友可以參考下
    2023-10-10
  • Nginx基于漏桶算法配置限流詳解

    Nginx基于漏桶算法配置限流詳解

    這篇文章主要為大家介紹了Nginx基于漏桶算法配置限流詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-10-10
  • nginx反向代理jupyter實踐

    nginx反向代理jupyter實踐

    文章講述了如何配置Jupyter Notebook,包括打開配置文件和設(shè)置反向代理,反向代理配置中提到,指定HTTP版本為1.1是必要的,因為如果不加,Notebook將無法連接到內(nèi)核并一直顯示斷開,此外,還提到了資源和瀏覽器禁止下載的問題
    2026-03-03
  • Nginx處理請求時的匹配規(guī)則詳析

    Nginx處理請求時的匹配規(guī)則詳析

    這篇文章主要給大家介紹了關(guān)于Nginx處理請求時的匹配規(guī)則的相關(guān)資料,文中通過示例代碼介紹的非常詳細,對大家學習或者使用Nginx具有一定的參考學習價值,需要的朋友們下面來一起學習學習吧
    2019-11-11
  • centos 7.0 使用Nginx部署flask應(yīng)用教程

    centos 7.0 使用Nginx部署flask應(yīng)用教程

    這篇文章主要介紹了centos 7.0 使用Nginx部署flask應(yīng)用教程,需要的朋友可以參考下
    2017-12-12
  • 詳解nginx同一端口監(jiān)聽多個域名和同時監(jiān)聽http與https

    詳解nginx同一端口監(jiān)聽多個域名和同時監(jiān)聽http與https

    這篇文章主要介紹了詳解nginx同一端口監(jiān)聽多個域名和同時監(jiān)聽http與https的相關(guān)資料,需要的朋友可以參考下
    2017-05-05

最新評論

罗平县| 新乡县| 大港区| 兰州市| 英山县| 乐都县| 敦煌市| 新河县| 轮台县| 沙湾县| 阳东县| 晋中市| 项城市| 乐陵市| 西乡县| 芦溪县| 新安县| 彭州市| 正镶白旗| 屯留县| 达日县| 柯坪县| 南澳县| 五寨县| 大名县| 伊宁市| 清镇市| 杂多县| 甘肃省| 丽江市| 靖宇县| 凭祥市| 全州县| 临高县| 富裕县| 芒康县| 宜丰县| 郸城县| 泗水县| 安图县| 永和县|