nginx add_header 不工作

Posted

技术标签:

【中文标题】nginx add_header 不工作【英文标题】:nginx add_header not working 【发布时间】:2013-08-26 18:11:08 【问题描述】:

我遇到了一个有趣的问题,每当我在运行带有 php 和 php-fpm 的 nginx 的 ubuntu 服务器上的虚拟主机配置中使用 add_header 时,它根本不起作用,我不知道我做错了什么。这是我的配置文件:

server 
    listen   80; ## listen for ipv4; this line is default and implied
    #listen   [::]:80 default ipv6only=on; ## listen for ipv6

    root /var/www/example.com/webroot/;
    index index.html index.htm index.php;

    # Make site accessible from http://www.example.com/
    server_name www.example.com;

    # max request size
    client_max_body_size 20m;

    # enable gzip compression
    gzip             on;
    gzip_static      on;
    gzip_min_length  1000;
    gzip_proxied     expired no-cache no-store private auth;
    gzip_types       text/plain text/css application/x-javascript text/xml application/xml application/xml+rss text/javascript;

    add_header 'Access-Control-Allow-Origin' '*';
    add_header 'Access-Control-Allow-Credentials' 'true';
    add_header 'Access-Control-Allow-Headers' 'Authorization,Content-Type,Accept,Origin,User-Agent,DNT,Cache-Control,X-Mx-ReqToken';
    add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, PUT, DELETE';
    add_header PS 1

    location / 
            # First attempt to serve request as file, then
            # as directory, then fall back to index.html
            try_files $uri $uri/ /index.php?$query_string;
            # Uncomment to enable naxsi on this location
            # include /etc/nginx/naxsi.rules
    


    location ~* \.(css|js|asf|asx|wax|wmv|wmx|avi|bmp|class|divx|doc|docx|eot|exe|gif|gz|gzip|ico|jpg|jpeg|jpe|mdb|mid|midi|mov|qt|mp3|m4a|mp4|m4v|mpeg|mpg|mpe|mpp|odb|odc|odf|odg|odp|ods|odt|ogg|ogv|$
            # 1 year -> 31536000
            expires 500s;
            access_log off;
            log_not_found off;
            add_header Pragma public;
            add_header Cache-Control "max-age=31536000, public";
    
    # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
    location ~ \.php$ 
            fastcgi_split_path_info ^(.+\.php)(/.+)$;
            # NOTE: You should have "cgi.fix_pathinfo = 0;" in php.ini

            # With php5-cgi alone:
            #fastcgi_pass 127.0.0.1:9000;
            # With php5-fpm:
            fastcgi_pass unix:/var/run/example.sock;
            fastcgi_index index.php?$query_string;
            include fastcgi_params;

            # instead I want to get the value from Origin request header
    

    # Deny access to hidden files
    location ~ /\. 
            deny all;
            access_log off;
            log_not_found off;
    

    error_page 403 /403/;


server 
    listen 80;
    server_name example.com;
    rewrite     ^ http://www.example.com$request_uri? permanent;

我尝试将标题添加到其他位置部分,但结果相同。

任何帮助表示赞赏!

【问题讨论】:

【参考方案1】:

对我来说有两个问题。

一个是 nginx 只处理 last add_header 它在树上发现的。因此,如果您在server 上下文中有一个add_header,然后在location 嵌套上下文中有另一个add_header,它将只处理location 上下文中的add_header 指令。只有最深的上下文。

来自 add_header 上的 NGINX 文档:

可能有多个 add_header 指令。当且仅当在当前级别上没有定义 add_header 指令时,这些指令才从上一层继承。

第二个问题是我的location / 块实际上正在将nginx 发送到另一个location ~* (\.php)$ 块(因为它会通过index.php 重新路由所有请求,这实际上使nginx 处理这个php 块)。所以,我在第一个 location 指令中的add_header 指令没有用,在我将所有需要的指令放入 php location 指令后它开始工作。

最后,这是我的工作配置,允许在名为 Laravel 的 MVC 框架的上下文中使用 CORS(您可以轻松更改此配置以适应任何将 index.php 作为所有请求的单一入口点的 PHP 框架)。

服务器 根 /path/to/app/public; 索引 index.php; server_name test.dev; # 重定向到 index.php 地点 / try_files $uri $uri/ /index.php?$query_string; # 将 PHP 脚本传递给在 127.0.0.1:9000 上监听的 FastCGI 服务器 位置 ~ \.php$ fastcgi_split_path_info ^(.+\.php)(/.+)$; # 注意:你应该有“cgi.fix_pathinfo = 0;”在 php.ini 中 # 使用 php5-fpm: fastcgi_pass unix:/var/run/php5-fpm.sock; fastcgi_index index.php; 包括 fastcgi_params; #cors配置 # 允许域的白名单,通过正则表达式 # if ($http_origin ~* (http://localhost(:[0-9]+)?)) if ($http_origin ~* .*) # 是的,用于本地开发。根据需要定制您的正则表达式 设置 $cors "true"; # 显然,以下三个 if 语句为“复合条件”创建了一个标志 如果($request_method = 选项) 设置 $cors "$corsoptions"; 如果($request_method = GET) 设置 $cors "$corsget"; 如果($request_method = POST) 设置 $cors "$corspost"; # 现在处理标志 if ($cors = 'trueget') add_header '访问控制允许来源' "$http_origin"; add_header '访问控制允许凭据' 'true'; if ($cors = 'truepost') add_header '访问控制允许来源' "$http_origin"; add_header '访问控制允许凭据' 'true'; if ($cors = 'trueoptions') add_header '访问控制允许来源' "$http_origin"; add_header '访问控制允许凭据' 'true'; add_header '访问控制-最大年龄' 1728000; # 缓存预检值 20 天 add_header '访问控制允许方法' 'GET,POST,OPTIONS'; add_header 'Access-Control-Allow-Headers' '授权,Content-Type,Accept,Origin,User-Agent,DNT,Cache-Control,X-Mx-ReqToken,Keep-Alive,X-Requested-With,If-Modified -自从'; add_header '内容长度' 0; add_header 'Content-Type' 'text/plain charset=UTF-8'; 返回204; 错误日志/var/log/nginx/test.dev.error.log; access_log /var/log/nginx/test.dev.access.log;

以上内容的要点在:https://gist.github.com/adityamenon/6753574

【讨论】:

谢谢,这帮助我解决了我的问题。我在 nginx.conf 中添加了一个标头,但它没有占用。读完后,我将 add_header 移动到特定的 sites_available 配置文件中,然后它就起作用了。 index.php 路由处理也让我很着迷。谢谢! 我也有类似的问题。只是添加一些重要的东西:相同的规则在 if 语句中也是有效的 - 你必须在那里添加所有“add_header”语句 这确实使我免于对某些 php 文件进行讨厌的 hack。谢谢! 请使用github.com/yandex/gixy 之类的东西来验证您的 nginx.conf - 显示哪个标头被丢弃等。【参考方案2】:

当我测试上述add_header 设置时:

# nginx -t && service nginx reload

我明白了

nginx: [emerg] directive "add_header" is not terminated by ";" in
/etc/nginx/enabled-sites/example.com.conf:21

nginx: configuration file /etc/nginx/nginx.conf test failed

所以抱怨是针对这一行的:

add_header PS 1

缺少分号 (;)

测试我喜欢使用的标题

# curl -I http://example.com

根据ngx_http_headers_module manual

syntax: add_header name value;
default:     —
context:    http, server, location, if in location

我进一步尝试

add_header X-test-A 1;
add_header "X-test-B" "2";
add_header 'X-test-C' '3';

httpserverlocation的上下文中,但它只出现在server上下文中。

【讨论】:

【参考方案3】:

由于响应代码不在允许的范围内,我遇到了无法获取响应标头的问题,除非您在标头值之后指定“always”关键字。

From the official docs:

如果响应代码等于 200、201、204、206、301、302、303、304、307 或 308,则将指定字段添加到响应标头。该值可以包含变量。

【讨论】:

【参考方案4】:

首先,让我说,在浏览了网络之后,我发现到处都是这个答案:

location ~* \.(eot|ttf|woff|woff2)$ 
    add_header Access-Control-Allow-Origin *;

但是,我决定用一个单独的答案来回答这个问题,因为我在花了大约十多个小时寻找解决方案后才设法让这个特定的解决方案工作。

Nginx 似乎默认没有定义任何 [正确的] 字体 MIME 类型。通过关注this tuorial,我发现我可以添加以下内容:

application/x-font-ttf           ttc ttf;
application/x-font-otf           otf;
application/font-woff            woff;
application/font-woff2           woff2;
application/vnd.ms-fontobject    eot;

到我的etc/nginx/mime.types 文件。如前所述,上述解决方案随后奏效。显然,这个答案旨在共享字体,但值得注意的是,MIME 类型可能未在 Nginx 中定义。

【讨论】:

设置 MIME 类型解决了这个问题。谢谢@DazBaldwin。 我刚刚节省了很多时间。谢谢!【参考方案5】:

显然 add_header 继承怪癖/陷阱也适用于上游层。

我有一个脚本对另一个服务的请求进行预授权,因此返回了来自另一个服务的所有标头。

一旦我开始添加“Access-Control-Allow-Origin”条目以及这些中继的标头,浏览器实际上会获取该条目并允许请求。

【讨论】:

【参考方案6】:

我认为重新加载无法正常工作 ==> nginx -s reload

当我使用 add_header 然后重新加载时,响应没有任何变化。 但是当我故意犯错误,在客户端看到404错误时, 然后修复了我故意的错误并再次重新加载,Add_header 工作。

【讨论】:

【参考方案7】:

你的 nginx 错误日志是怎么说的?

您知道哪些 add_header 行破坏了配置吗?如果没有,请将它们全部注释掉,然后逐个启用它们,重新加载 nginx 以查看哪些是/是问题。我将首先注释掉该块:

add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Credentials' 'true';
add_header 'Access-Control-Allow-Headers' 'Authorization,Content-Type,Accept,Origin,User-Agent,DNT,Cache-Control,X-Mx-ReqToken';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, PUT, DELETE';
add_header PS 1

问题可能是您设置了核心 httpHeaders 模块不支持的标头。安装NginxHttpHeadersMoreModule 可能会有所帮助。

另外,尝试将 location ~* \... 中的两个 add_header 行替换为以下内容:

add_header Pragma '';
add_header Cache-Control 'public, max-age=31536000'

你有 gzip 配置而不是你的全局 nginx.conf 有什么原因吗?

【讨论】:

我不认为 httpHeaders 对它添加的标题有选择性。【参考方案8】:

事实证明,尝试将 nginx 更新到最新版本是导致此问题的原因。我之前曾尝试重新安装,这似乎可以正确重新安装,但实际上 Ubuntu 并没有正确删除 nginx。所以我所要做的就是重新安装 Ubuntu 服务器并使用标准的 ubuntu 存储库重新安装所有内容。

【讨论】:

这实际上是指重新安装nginx而不回答根本原因时标记为正确答案。您的问题缺少详细信息,哪些标题不起作用以及您将它们添加到哪个其他位置但没有解决您的预期结果。

以上是关于nginx add_header 不工作的主要内容,如果未能解决你的问题,请参考以下文章

History Router Nginx 配置

nginx add_header Set-Cookie 过期不起作用

Nginx add_header 和缓存控制

Nginx指令add_header和proxy_set_header的区别

nginx 实现跨域

Nginx add_header Sec-WebSocket-Protocol 不起作用