71

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

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;
}

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

任何帮助表示赞赏!

4

8 回答 8

125

我有两个问题。

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

来自 add_header 上的 NGINX文档

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

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

最后,这是我的工作配置,允许在名为 Laravel 的 MVC 框架的上下文中使用 CORS(您可以轻松地更改它以适应任何 PHP 框架,该框架具有index.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 "${cors}options";
        }

        如果($request_method = GET){
            设置 $cors "${cors}get";
        }

        如果($request_method = POST){
            设置 $cors "${cors}post";
        }

        # 现在处理标志
        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

于 2013-10-02T11:19:19.623 回答
30

当我测试上述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 手册

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';

在,和的上下文中http,但它只出现在上下文中。serverlocationserver

于 2013-09-29T20:48:21.083 回答
29

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

来自官方文档:

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

于 2017-07-04T07:30:38.880 回答
6

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

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

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

默认情况下,Nginx 似乎没有定义任何 [正确] 字体 MIME 类型。通过遵循这个教程,我发现我可以添加以下内容:

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 中定义。

于 2017-01-04T15:37:42.670 回答
1

显然 add_header 继承 quirk/gotcha 也适用于上游层。

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

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

于 2017-01-06T19:29:02.053 回答
0

我认为通过重新加载 ==> nginx -s reload 不能正常工作

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

于 2020-04-04T18:50:59.607 回答
-1

你的 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可能会有所帮助。

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

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

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

于 2013-09-29T20:42:33.047 回答
-3

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

于 2013-10-03T09:05:02.960 回答