Nginx 跨域与反向代理

网上大部分关于 CROS 配置的文章都是有问题的,有些新版本不兼容,有些没有任何校验大门全开。

背景

解决 Flutter Web 本地调试连接 Tomcat 的跨域问题。跨域自身相关问题可参见 阮一峰的博客

安装

Archlinux:# sudo pacman -S nginx

安装完成后会自动创建 nginx systemd,默认是 stop, disable 的。

配置

详细的配置指导可参见 Nginx 官方文档

Archlinux extra 源内安装的 Nginx 的配置文件为 /etc/nginx/nginx.conf

启动并查看一下状态:# sudo systemctl start nginx && sudo systemctl status nginx

不出意外 Nginx 状态会是 running 的,但是可能会有一行 WARNING 日志 [warn] 6507#6507: could not build optimal types_hash, you should increase either types_hash_max_size: 1024 or types_hash_bucket_size: 64; ignoring types_hash_bucket_size,按照 archlinux wiki,需要修改配置文件 # sudo vim /etc/nginx/nginx.conf

    # http 节点下新增
    types_hash_max_size 4096;
    server_names_hash_bucket_size 128;

再次重启查看一下,应该就完全正常了 # sudo systemctl restart nginx && systemctl status nginx

反向代理配置

后台 REST API 启动 URL:http://127.0.0.1:8080

预置 Nginx 代理启动 URL 为:http://127.0.0.1:80

Tomcat 已提前安装,无多余配置,参考 Archlinux Wiki 即可,需要确保 Tomcat 配置文件 /etc/tomcat8/server.xmlHost 节点 name 属性与 Nginx 配置文件 /etc/nginx/nginx.conf 中配置的 server 节点 server_name 一致。

可以通过配置多个 Server 节点的方式做反向代理,但是我这里 Nginx 只做反向代理只用,不处理其他资源,所以先删除了默认的 Server 节点,# sudo vim /etc/nginx/nginx.conf,删除已有的 http 节点下的 server 节点,删除之后再新增反向代理的 Server 配置:

...
    # http 节点下新增
    # Reverse proxy for Tomcat
    upstream tomcat {
        server 127.0.0.1:8080;
    }   
    server {
        listen  80; 
        server_name localhost;
        location / { 
            proxy_set_header  Host $http_host;
            proxy_set_header  X-Real-IP $remote_addr;
            proxy_set_header  X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header  X-NginX-Proxy true;
            proxy_pass http://tomcat;
        }
    } 
...

重启查看一下 # sudo systemctl restart nginx && systemctl status nginx,浏览器直接访问 127.0.0.1,如果 Tomcat 未启动会返回一个 502,如果启动的话就会返回 Tomcat 相应的内容。

跨域配置

建议提前阅读 Nginx 的 If is Evil,这东西很坑,简单来说就是 location 配置不会继承,而 if 会生成一个匿名 location。

修改配置文件:# sudo vim /etc/nginx/nginx.conf,参数都比较简单,按需更改即可

...
    # http 节点下增加
    map $http_origin $access_host {
        default unauthorized;
        "~^http://127.0.0.1:d*$"   $http_origin;
        "~^http://localhost:d*$"  $http_origin;
    }
    ...
            # http -> server -> location / 节点下新增
            # CORS
            add_header 'Access-Control-Allow-Origin' $access_host always;
            add_header 'Access-Control-Allow-Credentials' 'true' always;
            add_header 'Access-Control-Allow-Headers' '*' always;
            add_header 'Access-Control-Allow-Methods' '*' always;
            # Required to be able to read Authorization or others header 
            #add_header 'Access-Control-Expose-Headers' 'Authorization' always;
            if ($request_method = 'OPTIONS') {
                return 204;
            }
            ...            

重启查看一下 # sudo systemctl restart nginx && systemctl status nginx,启动一个跨域的前端代码试试吧。

完整配置

#user html;
worker_processes  1;

#error_log  logs/error.log;
#error_log  logs/error.log  notice;
#error_log  logs/error.log  info;

#pid        logs/nginx.pid;


events {
    worker_connections  1024;
}


http {
    include       mime.types;
    default_type  application/octet-stream;

    #log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
    #                  '$status $body_bytes_sent "$http_referer" '
    #                  '"$http_user_agent" "$http_x_forwarded_for"';

    #access_log  logs/access.log  main;

    sendfile        on;
    #tcp_nopush     on;

    #keepalive_timeout  0;
    keepalive_timeout  65;

    #gzip  on;
    
    types_hash_max_size 4096;
    server_names_hash_bucket_size 128;

    map $http_origin $access_host {
        default unauthorized;
        "~^http://127.0.0.1:d*$"   $http_origin;
        "~^http://localhost:d*$"  $http_origin;
    }
    
    upstream tomcat {
        server localhost:8080;
    }

    server {
        listen  80;
        server_name localhost;
        
        location / {
            # Reverse proxy
            proxy_set_header  Host $http_host;
            proxy_set_header  X-Real-IP $remote_addr;
            proxy_set_header  X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header  X-NginX-Proxy true;
            proxy_pass http://tomcat;
            # CORS
            add_header 'Access-Control-Allow-Origin' $access_host always;
            add_header 'Access-Control-Allow-Credentials' 'true' always;
            add_header 'Access-Control-Allow-Headers' '*' always;
            add_header 'Access-Control-Allow-Methods' '*' always;
            # Required to be able to read Authorization or others header 
            #add_header 'Access-Control-Expose-Headers' 'Authorization' always;
            if ($request_method = 'OPTIONS') {
                return 204;
            }
        }
    }

#    server {
#        listen       80;
#        server_name  localhost;
#
#        #charset koi8-r;
#
#        #access_log  logs/host.access.log  main;
#
#        location / {
#            root   /usr/share/nginx/html;
#            index  index.html index.htm;
#        }
#
#        #error_page  404              /404.html;
#
#        # redirect server error pages to the static page /50x.html
#        #
#        error_page   500 502 503 504  /50x.html;
#        location = /50x.html {
#            root   /usr/share/nginx/html;
#        }
#
#        # proxy the PHP scripts to Apache listening on 127.0.0.1:80
#        #
#        #location ~ .php$ {
#        #    proxy_pass   http://127.0.0.1;
#        #}
#
#        # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
#        #
#        #location ~ .php$ {
#        #    root           html;
#        #    fastcgi_pass   127.0.0.1:9000;
#        #    fastcgi_index  index.php;
#        #    fastcgi_param  SCRIPT_FILENAME  /scripts$fastcgi_script_name;
#        #    include        fastcgi_params;
#        #}
#
#        # deny access to .htaccess files, if Apache's document root
#        # concurs with nginx's one
#        #
#        #location ~ /.ht {
#        #    deny  all;
#        #}
#    }


    # another virtual host using mix of IP-, name-, and port-based configuration
    #
    #server {
    #    listen       8000;
    #    listen       somename:8080;
    #    server_name  somename  alias  another.alias;

    #    location / {
    #        root   html;
    #        index  index.html index.htm;
    #    }
    #}


    # HTTPS server
    #
    #server {
    #    listen       443 ssl;
    #    server_name  localhost;

    #    ssl_certificate      cert.pem;
    #    ssl_certificate_key  cert.key;

    #    ssl_session_cache    shared:SSL:1m;
    #    ssl_session_timeout  5m;

    #    ssl_ciphers  HIGH:!aNULL:!MD5;
    #    ssl_prefer_server_ciphers  on;

    #    location / {
    #        root   html;
    #        index  index.html index.htm;
    #    }
    #}

}
原文地址:https://www.cnblogs.com/seliote/p/14322191.html