问题描述:

        nginx配置项目后通过域名访问项目时部分接口会出现403错误,charles抓包得到的response是阿里云的一个未备案的界面(但是真实的服务器确实接收到了请求并作出了正确的响应)。

        而通过nginx配置的server_name+监听的端口号去访问时,这部分接口却没有报错,charles抓包得到的响应是真实服务器给出的正确的响应。

问题原因:

        我这里出现这个问题的原因是:nginx配置了将客户端的host(域名访问时转发的就是域名)信息转发给服务器,访问项目的域名不是在阿里云备案的,但是报错的那几个接口是在阿里云服务器上,但阿里云服务器拒绝对未在它那里备案的域名发送响应。

解决办法:

更改配置不让nginx转发客户端host。

更改前:


worker_processes  1;

#工作模式与连接数上限
events {
    worker_connections  1024; # 单个进程最大连接数
}

#设定http服务器
http {
    include       mime.types;#文件扩展名与文件类型映射表
    default_type  application/octet-stream;#默认文件类型
    underscores_in_headers on;#允许请求中带有下划线

    sendfile        on;#开启高效文件传输模式,sendfile指令指定nginx是否调用sendfile函数来输出文件,对于普通应用设为 on,如果用来进行下载等应用磁盘IO重负载应用,可设置为off,以平衡磁盘与网络I/O处理速度,降低系统的负载。注意:如果图片显示不正常把这个改成off。
    keepalive_timeout  90;#长连接超时时间,单位是秒

    #虚拟主机的配置
    server {
        listen       9014;#监听的端口
        server_name  172.16.142.96;#空格隔开    
        client_header_buffer_size 32k;
        large_client_header_buffers 4 32k;

        location / {
            add_header Cache-Control no-cache;
            root html;#root安装目录
            try_files $uri $uri/ /index.html
            index index.html index.htm;
        }
        location /api {#反向代理
            proxy_set_header X-Real-IP $remote_addr;
            proxy_pass http://bbb.com.cn/api/;
            proxy_redirect off;
            rewrite ^.+hisESB/?(.*)$ /$1 break;
            #后端的Web服务器可以通过X-Forwarded-For获取用户真实IP
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header Host $http_host;
            proxy_set_header X-Nginx-Proxy true;
        }

        
        location /aliAPI {#反向代理
            proxy_set_header X-Real-IP $remote_addr;
            proxy_pass http://ali.com.cn/;
            proxy_redirect off;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header Host $host;
            proxy_set_header X-Nginx-Proxy true;
            client_max_body_size 10M;
            client_body_buffer_size 128k;
            add_header Access-Control-Allow-Origin *;
            add_header Access-Control-Allow-Headers X-Requested-With;
            add_header Access-Control-Allow-Methods GET,POST,OPTIONS;
        }
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }
    }
    
}

更改:删掉反向代理里的以下三个配置项

proxy_set_header  Host  $host;
proxy_set_header  X-real-ip $remote_addr;
proxy_set_header  X-Forwarded-For $proxy_add_x_forwarded_for;

【Nginx】Nginx反向代理转发Host设置 - willingtolove - 博客园

这个博客提到nginx默认是不会转发请求中的host的,而我一开始设置了会转发请求的host的,问题就出在这里。

更改后:


#user  nobody;
#nginx进程数,建议配置成CPU总核心数
worker_processes  1;

#error_log  logs/error.log;#全局错误日志定义类型,[ debug | info | notice | warn | error | crit ]
#error_log  logs/error.log  notice;
#error_log  logs/error.log  info;

#pid        logs/nginx.pid; # 进程文件


#工作模式与连接数上限
events {
    worker_connections  1024; # 单个进程最大连接数
}

#设定http服务器
http {
    include       mime.types;#文件扩展名与文件类型映射表
    default_type  application/octet-stream;#默认文件类型
    underscores_in_headers on;#允许请求中带有下划线

    sendfile        on;#开启高效文件传输模式,sendfile指令指定nginx是否调用sendfile函数来输出文件,对于普通应用设为 on,如果用来进行下载等应用磁盘IO重负载应用,可设置为off,以平衡磁盘与网络I/O处理速度,降低系统的负载。注意:如果图片显示不正常把这个改成off。

    keepalive_timeout  90;#长连接超时时间,单位是秒

    #虚拟主机的配置
    server {
        listen       9014;#监听的端口
        server_name  172.16.142.96;#空格隔开    
        client_header_buffer_size 32k;
        large_client_header_buffers 4 32k;

        location / {
            add_header Cache-Control no-cache;
            root html;#root安装目录
            try_files $uri $uri/ /index.html
            index index.html index.htm;
        }
        location /api {#反向代理
            proxy_pass http://bbb.com.cn/api/;
        }

        
        location /aliAPI {#反向代理
            proxy_pass http://ali.com.cn/;
        }
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }
    }
    
}

排查问题的过程:


        1、一开始考虑nginx是否有将请求转发给真实服务器,但是查看真实服务器的日志,发现接收到了请求并作出了正确响应,所以不是nginx肯定转发了这个请求。
        2、然后考虑是否是浏览器-nginx代理服务器-真实服务器,之间的连接在“返程”(真实服务器->代理服务器->浏览器发送响应)的时候出了问题,特意了解了下请求通过代理发送到服务器最后服务器发回响应的整个过程,发现可能不是这里的问题。
        3、尝试直接使用nginx配的ip+端口号去访问项目,发现这几个接口正常了。于是怀疑是域名和这个ip+端口号的映射的问题。问了同事是怎么映射的时候,他讲了就是DNS映射到外网地址,外网地址NAT映射到nginx配的server_name的ip上(这里解析的过程我不是很懂,但是项目能通过域名访问,应该就能说明域名和ip是映射到了的)。不过此时同事提到防火墙有拦截一些请求,会不会是这个原因,但是拦截掉的请求是不会发送到服务器去的,而查看日志发现服务器是能接收到请求的,所以排除。(如果服务器没接收到请求,那可以查看下请求有没有被防火墙拦截)
        4、到这里我可以确定是通过域名访问时这几个接口才报403错误,ip+端口号访问没错,所以此时认为代码和nginx配置应该没错。猜测这几个接口所在的服务器拒绝给该域名做出响应。但是为什么拒绝我也不是很了解,就陷入了这个死胡同,感觉是域名的问题。然后我去找了下报错的几个接口的共同点——都在阿里云的服务器上。我把情况上报给组长,组长帮忙排查了下,说是访问项目的这个域名没有在阿里云上备案,可能是在其他地方备案的(我也不太懂),所以才会返回一个未备案的界面。


        5、此时,我以为解决办法是换一个在阿里云备案的域名来映射nginx服务器的ip+端口号。但是由于这个域名是甲方提供的,秉着有问题不能总想着麻烦甲方的精神,此路不通。
        6、所以换个方向想,阿里云拒绝对未备案的域名发来的请求做出响应,那我配置nginx的时候不让阿里云服务器知道这个请求的来源是这个域名不就好了?所以百度一下发现nginx默认是不会转发客户端的请求头的。然后查看我的nginx配置发现我确实将客户端请求的host转发给服务器了,原来问题在这里!赶紧删掉多余的配置,重启运行,问题果然解决了!


害,绕了个大圈,问题还是出在我配置的nginx上,惭愧啊。以上思路有哪里理解错了,请大佬们指点指点我啊

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐