网管把PUT请求禁掉非说是我们接口的问题---nginx 请求转发就完了?各种奇技淫巧等你来

4,609 阅读5分钟

开发是项目的成型的第一步,项目内部、外部统一话接口还得借助nginx 这种请求转发工具,因为你无法保证项目的单一性,我们整个项目可能用到各种各样的技术。

Nginx配置proxy_pass转发的/路径问题

在nginx中配置proxy_pass时,如果是按照^~匹配路径时,要注意proxy_pass后的url最后的/,当加上了/,相当于是绝对根路径,则nginx不会把location中匹配的路径部分代理走;如果没有/,则会把匹配的路径部分也给代理走。

location ^~ /static_js/ 
{ 
proxy_cache js_cache; 
proxy_set_header Host js.test.com; 
proxy_pass http://js.test.com/; 
}

如上面的配置,如果请求的url是http://servername/static_js/test.html 会被代理成js.test.com/test.html

而如果这么配置

location ^~ /static_js/ 
{ 
proxy_cache js_cache; 
proxy_set_header Host js.test.com; 
proxy_pass http://js.test.com; 
}

则会被代理到js.test.com/static_js/t…

root alias 区别

location /test/{
    root /home/china/areas/;
}

访问 localhost***/test/hello.html实际访问的是 /home/china/areas/test/hello.html

location /tets/{
    alias /home/china/areas/;
}

访问 localhost***/test/hello.html实际访问的是 /home/china/areas/hello.html

server_name 的使用

  • 之前我一直认为这里的 server_name 就是方便我们访问的域名。其实并不是这么回事。不信你配置好之后在浏览器中访问根本是访问不同的。

  • 首先我们得明白我们请求的域名是需要经过 DNS 解析的。和 nginx 是无关的。本地的 DNS 解析就是本地的 /etc/hosts 文件。

server {
  listen 88;
  listen [::]:88;

  server_name www.zxhtom.com;

  root /var/www/html;
  index index.html;

  location / {
    try_files $uri $uri/ =404;
  }
}

server {
  listen 88;
  listen [::]:88;

  server_name www.zxhtom.cn;

  root /var/www/example.com;
  index index.html;

  location / {
    try_files $uri $uri/ =404;
  }
}

  • 上面我配置了两个 server 可能你会觉得奇怪,为什么两个 server 都是监听88端口呢?仔细观察你会发现他们的 server_name 不同。
  • 接下来我们在本地配置这两个域名的解析
127.0.0.1 www.zxhtom.com
127.0.0.1 www.zxhtom.cn
  • 访问两个域名对应的 88端口,我们能够发现对应的是不同的页面。到这里你应该明白 server_name 的作用的吧。

20230613-154934548.png

  • 上述的配置同时对 127.0.0.1 的使用也没啥影响。

20230613-155135330.png

  • 配置了专属域名如果此时 hosts 文件中配置了另外一个域名 www.zxhtom.store 那么是否还需要在另行配置呢?答案是否定的。
  • 当出现新的域名访问 nginx 的时候,nginx 会去寻找配置了 default_server 的 server 。如上我们两个 server 都没有配置 default_server . nginx 会按照顺序选取第一个。换句话说我们 www.zxhtom.store 对应的是 www.zxhtom.com server_name 的配置。如果我们想让 www.zxhtom.cn 作为默认的,我们可以将他配置在地一个。或者修改成如下配置
server {
  listen 80 default_server;
  listen [::]:80 default_server;

  server_name www.zxhtom.cn;
  charset utf-8;
  root /home/zxhtom/temp/html;
  index index.html;
}

中文乱码

  • 上面我们能够发现,我们自定义的页面显示的是乱码。

20230613-155423585.png

SSL

  • google 浏览器带头限制 http 请求,关于网站 SSL 证书的配置尤为重要。下面我们通过 nginx 来配置下 SSL

20230614-092415875.png

  • 阿里云域名服务地方可以申请免费的 SSL 证书。申请之后可以按照阿里官方的教程配置
server {
	# SSL configuration
	#
	listen 443 ssl ;
	listen [::]:443 ssl ;
  server_name www.zxhtom.cn;
  #填写证书文件名称
  ssl_certificate cert/<domain_name>.pem;
  #填写证书私钥文件名称
  ssl_certificate_key cert/<domain_name>.key;

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

  #默认加密套件
  ssl_ciphers HIGH:!aNULL:!MD5;

  #自定义设置使用的TLS协议的类型以及加密套件(以下为配置示例,请您自行评估是否需要配置)
  #TLS协议版本越高,HTTPS通信的安全性越高,但是相较于低版本TLS协议,高版本TLS协议对浏览器的兼容性较差。
  #ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;
  #ssl_protocols TLSv1.1 TLSv1.2 TLSv1.3;

  #表示优先使用服务端加密套件。默认开启
  ssl_prefer_server_ciphers on;

  location / {

    default_type application/json;
    return 200 '{"status":"success","result":"welcom https cn"}';
    # try_files $uri $uri/ =404;
    # proxy_pass http://192.168.0.190;
  }
}

  • 结合上面我们描述的 server_name 的功能,我们上述的配置就是支持 https://www.zxhtom.cn 的请求访问。当我们访问该地址就会返回 welcom https cn 等信息。

接口 413 错误

  • 413 Request Entity Too Large 。根据提示第一反应就是请求体过大。但是我的报错是 GET 请求,仔细观察下 GET 请求没啥参数传递的。不管三七二十一先按照网上的进行修改下。
413 Request Entity Too Large
location /zxhtom/latest/{
	proxy_set_header Host $http_host;
	proxy_set_header X-Real-IP $remote_addr;
	proxy_set_header REMOTE-HOST $remote_addr;
	proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
	client_max_body_size 800m;
	proxy_pass http://www.zxhtom.com/;
}
  • 只需要添加 client_max_body_size 参数即可放开我们请求体的数据了。但是还是解决不了我的问题,而且 client_max_body_size 根绝名字猜测应该是请求数据大小的设置,应该主要使用的场景是文件上传才需要设置,正常数据怎么会有几百 M 呢?
  • 在分析下自己的数据发现因为接口需要登录请求头中 JWT 的 token 特别的长。于是搜索了下 nginx 是否可以调整请求头大小。
client_header_buffer_size 16k;
large_client_header_buffers 4 16k;
  • 设置了之后还是不行,于是将焦点下放到网关层面上 http://www.zxhtom.com。于是我跳过 nginx 单独访问网管发现报错 400 。他的报错突然让我坚定了自己的猜想,我们的网关是通过 SpringCloud Gateway 实现的。
server:
	max-http-header-size: 2MB
@Component
public class NettyConfiguration implements WebServerFactoryCustomizer<NettyReactiveWebServerFactory> {

    @Override
    public void customize(NettyReactiveWebServerFactory container) {
        container.addServerCustomizers(
                httpServer -> httpServer.httpRequestDecoder(
                        httpRequestDecoderSpec -> httpRequestDecoderSpec.maxHeaderSize(1000485760)
                )
        );
    }

}
  • 在网关中添加如上配置即可解决 413 问题。

PUT/DELETE 接口 Empty reply

  • 由于政务系统对安全性的要求,在他们网络层面上将 PUT 、DELETE 这两种请求给禁掉了。而我们系统中存在大面积的这样的请求,如果改的话工作量巨大而且容易遗漏,后来找到一中通过 nginx 转发的方案来解决这个问题。
set $method $request_method;
      if ($http_X_HTTP_Method_Override ~* 'DELETE'){
       set $method DELETE;

      }
      if ($http_X_HTTP_Method_Override ~* 'PUT'){
       set $method PUT;

      }
      proxy_method $method;
  • 加上上面这段配置后重启 nginx ,原本的 PUT 接口我们只需要修改为 POST,并且请求头中添加 X-HTTP-Method-Override:PUT 即可。

curl -XPUT 'http://www.zxhtom.com/pre/userList'
  • 只需要改为
curl -XPOST 'http://www.zxhtom.com/pre/userList' -H'X-HTTP-Method-Override:PUT'