浏览器给出CORS错误,尽管在Nginx中添加了CORS头

pxy2qtax  于 2023-08-03  发布在  Nginx
关注(0)|答案(1)|浏览(270)

我已经为内部IP 192.168.1.119添加了一个主机条目,作为/etc/hosts中的multiserver.billinghub.net
当我访问 http:multiserver.billinghub.net/test/customer-portal时,它对http://multiserver.billinghub.net/jbilling/api/authentication/authenticate进行内部调用,由于域相同,浏览器不会标记XHR调用。
但是当我使用IP地址而不是域名http://192.168.1.119/test/customer-portal时,内部调用使用的是multiserver.billinghub.net,这被视为CORS请求并被浏览器阻止。
我在后端使用Nginx来反向代理请求,并添加了必要的CORS头来解决上述问题。这是我的nginx配置,灵感来自这个要点评论。

upstream customer-portal {
  random two least_conn;
  server 192.168.1.119:8087;
  server 192.168.1.113:8087;
  keepalive 4;
}

upstream jbilling {
  hash $binary_remote_addr consistent;
  server 192.168.1.119:8080;
  server 192.168.1.113:8080;
  keepalive 4;
}

map $http_origin $cors_origin_header {
    default "";
    "~(^|^http:\/\/)(localhost$|localhost:[0-9]{1,4}$)" "$http_origin";
    "http://multiserver.billinghub.net" "$http_origin"; 
    "http://192.168.1.119" "$http_origin";
}

map $http_origin $cors_cred {
    default "";
    "~(^|^http:\/\/)(localhost$|localhost:[0-9]{1,4}$)" "true";
    "http://multiserver.billinghub.net" "true"; 
    "http://192.168.1.119" "true";
}

## Server block with port and redirect config
server {

  listen 80 reuseport; 
  server_name multiserver.billinghub.net; 
  gzip on;
  gzip_types application/xml;
  gzip_min_length 1000;

  add_header 'Access-Control-Allow-Origin' '$cors_origin_header' always;
  add_header 'Access-Control-Allow-Credentials' '$cors_cred' always;
  add_header 'Access-Control-Allow-Methods' "GET, HEAD, POST, PUT, DELETE, TRACE, OPTIONS, PATCH" always;
  add_header 'Access-Control-Allow-Headers' "Accept, Accept-Language, Content-Language, Content-Type, authorization, Origin, Referer, User-Agent, Cache-Control, DNT, If-Modified-Since, Cache-Control, Range, Uuid" always;
  add_header 'Access-Control-Expose-Headers' '*' always;
  
  if ($request_method = 'OPTIONS' ) {
      return 204 no-content;
  }

location /test/customer-portal {
    proxy_set_header        Host $host:$server_port;
    proxy_set_header        X-Real-IP $remote_addr;
    proxy_set_header        X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header        X-Forwarded-Proto $scheme;

    proxy_pass              http://customer-portal;

    # Required for new HTTP-based CLI
    proxy_http_version 1.1;
    proxy_set_header Connection "";
    proxy_request_buffering off;
    proxy_buffering off; # Required for HTTP-based CLI to work over SSL
    # set client body size to 2M #
    client_max_body_size 500M;    
  }

  location /jbilling {
    proxy_set_header        Host $host:$server_port;
    proxy_set_header        X-Real-IP $remote_addr;
    proxy_set_header        X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header        X-Forwarded-Proto $scheme;

    proxy_pass              http://jbilling;

    # Required for new HTTP-based CLI
    proxy_http_version 1.1;
    proxy_set_header Connection "";
    proxy_request_buffering off;
    proxy_buffering off; # Required for HTTP-based CLI to work over SSL
    # set client body size to 2M #
    client_max_body_size 500M;
  }
}

字符串
添加上述配置后,我仍然得到一个CORS错误,由于某种原因,我得到了多个值在Access-Control-Allow-Header像这样的

有人能告诉我知道我错过了什么吗?谢啦,谢啦

zd287kbt

zd287kbt1#

TL;DR

感谢我的好朋友Bharath,他建议将add_header指令从server级别移动到location级别,问题得到了解决。
由于重复add_header指令并不美观,所以我创建了一个cors.conf文件,并将其包含在location块中。

这是我的cors.conf文件:

add_header 'Access-Control-Allow-Origin' '$cors_origin_header' always;
  add_header 'Access-Control-Allow-Credentials' '$cors_cred' always;
  add_header 'Access-Control-Allow-Methods' "GET, HEAD, POST, PUT, DELETE, TRACE, OPTIONS, PATCH" always;
  add_header 'Access-Control-Allow-Headers' "Accept, Accept-Language, Content-Language, Content-Type, Authorization, Origin, Referer, User-Agent, Cache-Control, DNT, If-Modified-Since, Range" always;
  add_header 'Access-Control-Expose-Headers' '*' always;

  if ($request_method = 'OPTIONS' ) {
      return 204 no-content;
  }

字符串

更新nginx配置:(为简洁起见,不包括上游块)

map $http_origin $cors_origin_header {
    default "";
    "~(^|^http:\/\/)(localhost$|localhost:[0-9]{1,4}$)" "$http_origin";
    "http://multiserver.billinghub.net" "$http_origin"; 
    "http://192.168.1.119" "$http_origin";
}

map $http_origin $cors_cred {
    default "";
    "~(^|^http:\/\/)(localhost$|localhost:[0-9]{1,4}$)" "true";
    "http://multiserver.billinghub.net" "true"; 
    "http://192.168.1.119" "true";
}

## Server block with port and redirect config
server {

  listen 80 reuseport; 
  server_name multiserver.billinghub.net; 
  gzip on;
  gzip_types application/xml;
  gzip_min_length 1000;

location /test/customer-portal {
    proxy_set_header        Host $host:$server_port;
    proxy_set_header        X-Real-IP $remote_addr;
    proxy_set_header        X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header        X-Forwarded-Proto $scheme;

    proxy_pass              http://customer-portal;

    # Required for new HTTP-based CLI
    proxy_http_version 1.1;
    proxy_set_header Connection "";
    proxy_request_buffering off;
    proxy_buffering off; # Required for HTTP-based CLI to work over SSL
    # set client body size to 2M #
    client_max_body_size 500M;    
    include /etc/nginx/cors.conf; # <== included cors-related configurations
  }

  location /jbilling {
    proxy_set_header        Host $host:$server_port;
    proxy_set_header        X-Real-IP $remote_addr;
    proxy_set_header        X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header        X-Forwarded-Proto $scheme;

    proxy_pass              http://jbilling;

    # Required for new HTTP-based CLI
    proxy_http_version 1.1;
    proxy_set_header Connection "";
    proxy_request_buffering off;
    proxy_buffering off; # Required for HTTP-based CLI to work over SSL
    # set client body size to 2M #
    client_max_body_size 500M;
  }
}


PS:* 按照这个ServerFault answer使用ngx_headers_more模块构建Nginx也对我有用。*

为什么我首先在Access-Control-Allow-Origin中获得多个值?

当从customer-portal调用jBilling时,Nginx正在添加所需的CORS origin header,但当调用从上游jBilling -> Nginx -> customer-portal返回时
Nginx再次添加了CORS头,因此该值被重复,因为如果头存在,add_header指令不会覆盖该值。
add_header指令转移到location块时,根据Nginx,我们需要手动设置所有必要的头值。
我仍然觉得使用more_headers模块构建Nginx是解决这个问题的更好方法,因为使用ngx_headers_more模块可以获得更多功能。

更新:

我安装了headers-more-nginx-module并将其加载到我的nginx.conf中,这样我就不必维护一个单独的cors.conf(我在上面创建的那个),并且我可以直接在server级别设置必要的CORS头。
下面是我更新的nginx.conf:

user www-data;
worker_processes auto;
pid /run/nginx.pid;
include /etc/nginx/modules-enabled/*.conf;

# Compiled and added headers_more module https://github.com/openresty/headers-more-nginx-module#installation
load_module /etc/nginx/modules-available/ngx_http_headers_more_filter_module.so;

# number of file descriptors used for nginx
# The limit for the maximum FDs on the server is usually set by the OS.
# If you don't set FDs then OS settings will be used which is by default 2000
worker_rlimit_nofile 100000;

events {
    worker_connections 4096;
    use epoll;
    # multi_accept on;
}

http {

    ##
    # Basic Settings
    ##

    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;
    keepalive_timeout 65;
    types_hash_max_size 2048;
    # server_tokens off;

    # server_names_hash_bucket_size 64;
    # server_name_in_redirect off;

    include /etc/nginx/mime.types;
    default_type application/octet-stream;

    ##
    # SSL Settings
    ##

    ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; # Dropping SSLv3, ref: POODLE
    ssl_prefer_server_ciphers on;

    ##
    # Logging Settings
    ##

    access_log /var/log/nginx/access.log;
    error_log /var/log/nginx/error.log;

    ##
    # Gzip Settings
    ##

    gzip on;

    ##
    # Virtual Host Configs
    ##

    include /etc/nginx/conf.d/*.conf;
    include /etc/nginx/sites-enabled/*;
}


更新nginx配置:

upstream customer-portal {
  hash $binary_remote_addr consistent;
  server 192.168.1.119:8087;
  server 192.168.1.113:8087;
  keepalive 4;
}

upstream jbilling {
  hash $binary_remote_addr consistent;
  server 192.168.1.119:8080;
  server 192.168.1.113:8080;
  keepalive 4;
}

map $http_origin $cors_origin_header {
    default "";
    "~(^|^http:\/\/)(localhost$|localhost:[0-9]{1,4}$)" "$http_origin";
    "http://multiserver.billinghub.net" "$http_origin"; 
    "http://192.168.1.119" "$http_origin";
}

map $http_origin $cors_cred {
    default "";
    "~(^|^http:\/\/)(localhost$|localhost:[0-9]{1,4}$)" "true";
    "http://multiserver.billinghub.net" "true"; 
    "http://192.168.1.119" "true";
}

## Server block with port and redirect config
server {

  listen 80 reuseport; 
  server_name multiserver.billinghub.net; 
  gzip on;
  gzip_types application/xml;
  gzip_min_length 1000;

  # Setting Access-Control Headers
  more_set_headers 'Access-Control-Allow-Origin: $cors_origin_header';
  more_set_headers 'Access-Control-Allow-Credentials: $cors_cred';
  more_set_headers 'Access-Control-Allow-Methods: GET, HEAD, POST, PUT, DELETE, TRACE, OPTIONS, PATCH';
  more_set_headers 'Access-Control-Allow-Headers: Accept, Accept-Language, Content-Language, Content-Type,authorization, Origin, Referer, User-Agent, Cache-Control, DNT, If-Modified-Since, Cache-Control, Range, uuid';
  more_set_headers 'Access-Control-Expose-Headers: *';

# Allowing preflight request to pass through
if ($request_method = 'OPTIONS' ) {
    return 204 no-content;
}

location /test/customer-portal {
    proxy_set_header        Host $host:$server_port;
    proxy_set_header        X-Real-IP $remote_addr;
    proxy_set_header        X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header        X-Forwarded-Proto $scheme;

    proxy_pass              http://customer-portal;

    # Required for new HTTP-based CLI
    proxy_http_version 1.1;
    proxy_set_header Connection "";
    proxy_request_buffering off;
    proxy_buffering off; # Required for HTTP-based CLI to work over SSL
    # set client body size to 2M #
    client_max_body_size 500M;    
  }

  location /jbilling {
    proxy_set_header        Host $host:$server_port;
    proxy_set_header        X-Real-IP $remote_addr;
    proxy_set_header        X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header        X-Forwarded-Proto $scheme;

    proxy_pass              http://jbilling;

    # Required for new HTTP-based CLI
    proxy_http_version 1.1;
    proxy_set_header Connection "";
    proxy_request_buffering off;
    proxy_buffering off; # Required for HTTP-based CLI to work over SSL
    # set client body size to 2M #
    client_max_body_size 500M;
  }
}

相关问题