使用 nginx 代理在 node.js 应用上启用 Cors

Enable Cors on node.js app with nginx proxy

我已经设置了一个数字海洋水滴,它是一个使用 nginx 和节点的反向代理服务器。我使用数字海洋中的这个教程作为起点

https://www.digitalocean.com/community/tutorials/how-to-set-up-a-node-js-application-for-production-on-ubuntu-14-04

我还设置了 ssl 和 lets encrypt。我目前遇到的问题是我无法对服务器进行跨域 ajax 调用。我收到一个错误,显示没有 'Access-Control-Allow-Origin' header。我已经在我的节点应用程序中设置了适当的 header 响应,并尝试遵循我能为 nginx 找到的几个示例,但没有成功。下面是我的代码。

nginx 删除了我 header 的尝试

server {
listen 443 ssl;

server_name lefthookservices.com www.lefthookservices.com;

ssl_certificate /etc/letsencrypt/live/lefthookservices.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/lefthookservices.com/privkey.pem;

 ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_prefer_server_ciphers on;
    ssl_dhparam /etc/ssl/certs/dhparam.pem;
    ssl_ciphers 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-$
    ssl_session_timeout 1d;
    ssl_session_cache shared:SSL:50m;
    ssl_stapling on;
    ssl_stapling_verify on;
    add_header Strict-Transport-Security max-age=15768000;

location / {


    proxy_pass http://127.0.0.1:8080;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection 'upgrade';
    proxy_set_header Host $host;
    proxy_cache_bypass $http_upgrade;



}
  location ~ /.well-known {
           allow all;
    }

}

server {
    listen 80;
    server_name lefthookservices.com  www.lefthookservices.com;
    return 301 https://$host$request_uri;
}

这是我的 app.js 使用 express

的脚本
    'use strict';
var colors = require('colors/safe');

var express = require('express');

var knack = require('./knack_call.js');

var bodyParser = require('body-parser');

var cors = require('cors');

colors.setTheme({
  custom: ['blue', 'bgWhite']
});

var app = express();

app.use(bodyParser.json());


// allow for cross domain ajax

app.get('/',  function(request, response){

    response.send('hello\n');

});

app.post('/', function(request, response){

    response.header("Access-Control-Allow-Origin", "*");
    response.header("Access-Control-Allow-Headers", "X-Requested-With");
    response.header("Access-Control-Allow-Methods', 'GET,POST");

    knack.getData(request, response);
});

app.listen(8080, '127.0.0.1', function(m){
    console.log(colors.custom("Captin the server is at full strength"));
});

任何可以帮助我设置正确的 headers 以允许 CORS 的建议将不胜感激。提前谢谢你。

由于特里斯坦在下面的回答,我的 Nginx 代码现在看起来像这样。

server {
    listen 443 ssl;

    server_name lefthookservices.com www.lefthookservices.com;

    ssl_certificate /etc/letsencrypt/live/lefthookservices.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/lefthookservices.com/privkey.pem;

     ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
        ssl_prefer_server_ciphers on;
        ssl_dhparam /etc/ssl/certs/dhparam.pem;
        ssl_ciphers 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES$
        ssl_session_timeout 1d;
        ssl_session_cache shared:SSL:50m;
        ssl_stapling on;
        ssl_stapling_verify on;
        add_header Strict-Transport-Security max-age=15768000;

    location / {

        proxy_redirect off;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

        if ($http_origin ~*(https?://.*\exponential.singularityu\.org(:[0-9]+)?$)){
            set $cors "1";
        }
        if ($request_method = 'OPTIONS') {
             set $cors "${cors}o";
           }


        if ($cors = "1") {
          more_set_headers 'Access-Control-Allow-Origin: $http_origin';
          more_set_headers 'Access-Control-Allow-Credentials: true';
          proxy_pass      http://127.0.0.1:8080;
        }

        if ($cors = "1o") {
           more_set_headers 'Access-Control-Allow-Origin: $http_origin';
           more_set_headers 'Access-Control-Allow-Methods: GET, POST, OPTIONS, PUT, DELETE';
           more_set_headers 'Access-Control-Allow-Credentials: true';
           more_set_headers 'Access-Control-Allow-Headers: Origin,Content-Type,Accept';
           add_header Content-Length 0;
           add_header Content-Type text/plain;
           return 204;
         }

        proxy_pass http://127.0.0.1:8080;




    }
}
location ~ /.well-known {
           allow all;
    }

}

遗憾的是,这仍然无效。

server {
    listen 80;
    server_name lefthookservices.com  www.lefthookservices.com;
    return 301 https://$host$request_uri;
}

你快到了。

您必须将代理视为外部服务器以及您的 Node.js 应用程序。

因此,简而言之,您需要在 nginx 配置中添加 header。

看看这个link, https://gist.github.com/pauloricardomg/7084524

万一这被删除:

#
# Acts as a nginx HTTPS proxy server
# enabling CORS only to domains matched by regex 
# /https?://.*\.mckinsey\.com(:[0-9]+)?)/
#
# Based on: 
# * http://blog.themillhousegroup.com/2013/05/nginx-as-cors-enabled-https-proxy.html
# * http://enable-cors.org/server_nginx.html
#
server {
  listen 443 default_server ssl;
  server_name localhost;

  # Fake certs - fine for development purposes :-)
  ssl_certificate /etc/ssl/certs/ssl-cert-snakeoil.pem;
  ssl_certificate_key /etc/ssl/private/ssl-cert-snakeoil.key;

  ssl_session_timeout 5m;

  location / {
    proxy_redirect off;
    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

    # Nginx doesn't support nested If statements, so we
    # concatenate compound conditions on the $cors variable
    # and process later

    # If request comes from allowed subdomain
    # (*.mckinsey.com) then we enable CORS
    if ($http_origin ~* (https?://.*\.mckinsey\.com(:[0-9]+)?$)) {
       set $cors "1";
    }

    # OPTIONS indicates a CORS pre-flight request
    if ($request_method = 'OPTIONS') {
       set $cors "${cors}o";
    }

    # Append CORS headers to any request from 
    # allowed CORS domain, except OPTIONS
    if ($cors = "1") {
       more_set_headers 'Access-Control-Allow-Origin: $http_origin';
       more_set_headers 'Access-Control-Allow-Credentials: true';
       proxy_pass      http://serverIP:serverPort;
    }

    # OPTIONS (pre-flight) request from allowed 
    # CORS domain. return response directly
    if ($cors = "1o") {
       more_set_headers 'Access-Control-Allow-Origin: $http_origin';
       more_set_headers 'Access-Control-Allow-Methods: GET, POST, OPTIONS, PUT, DELETE';
       more_set_headers 'Access-Control-Allow-Credentials: true';
       more_set_headers 'Access-Control-Allow-Headers: Origin,Content-Type,Accept';
       add_header Content-Length 0;
       add_header Content-Type text/plain;
       return 204;
    }

    # Requests from non-allowed CORS domains
       proxy_pass      http://serverIP:serverPort;
  }
}

把 Nginx 从这个等式中拉出来。如果您的设置与我认为的一样相似,那么它与您的 COR 问题没有任何关系。我看到您正在使用 cors 模块,但我看到您实际上并没有使用它。

您的设置非常简单,您可以使用默认设置,因此,在 app.use(bodyParser.json()); 下方,将您的 app.js 更新为:

app.use(cors());

开箱即用。如果没有,您可以传递一组选项。我的看起来像这样:

app.use(cors({
    origin: myorigin.tld, 
    allowedHeaders: [ 'Accept-Version', 'Authorization', 'Credentials', 'Content-Type' ]
}));

文档中提供了其他配置选项。

事实证明我收到的错误消息不准确。问题不是 header 设置。事实证明,我需要使用 jsonp 发出请求,并且我需要以不同的方式处理传入的数据。 app.js 调用的函数出错导致连接超时。这导致适当的 headers 没有返回到导致错误消息的浏览器。

对于任何希望找到有效的 NGINX 配置的人来说,这是我的。

proxy_pass http://127.0.0.1:8080;
   # proxy_http_version 1.1;
    proxy_set_header Access-Control-Allow-Origin *;
   # proxy_set_header Upgrade $http_upgrade;
   # proxy_set_header Connection '';
    proxy_set_header Host $host;
   # proxy_cache_bypass $http_upgrade;

感谢您的建议。