Nginx 405 not allowed 异常处理记录

今天遇到一个问题,当配置好的前端工程放到服务器上使用nginx启动的时候,报了405 Not allowed 异常,在网上百度了一下,说是这个问题出现的原因是因为使用了post 请求去获取静态资源,我觉得很奇怪,请求的接口都是业务接口,并不存在请求静态资源,是不是nginx对静态资源理解有什么误会,或者说我对静态资源理解不对,抱着这个想法,我把静态资源的概念又梳理了一遍:

静态资源:指的就是在html中的js/css/jpg/png/xxx.json...等等这些在前端工程中需要提前配置或者编译之后的文件,而且这些文件并不会时刻变化或者说变化周期比较长

解决尝试

好的,接下来我就试着根据百度出来的解决办法都尝试了一遍,毕竟网上这么多提出解决办法的,总有一个能解决吧,于是就开始尝试了各种网友的解决办法:

  1. location中配置error_page,这个解决问题的思路是将post请求转换成get请求,配置信息如下:
server {
    listen       80;
    server_name  域名;
   location /{
       root /www/文件目录;
       index index.html index.htm index.php;
       error_page 405 =200 http://$host$request_uri;
    }
 }



这样写是有问题的,有网友提到这样写只适用于post请求中不带参数的请求,带参数的post请求如果使用这种方式可能会导致参数体丢失

2. 修改nginx下src/http/modules/ngx_http_static_module.c文件,如下:

if (r->method & NGX_HTTP_POST) {
     return NGX_HTTP_NOT_ALLOWED;
}


这个办法是修改nginx的源码,将这一段代码注释掉,重新编译,注意,注释的时候需要使用 /* */ 的方式,而不是 # 这个符号,不然会报错,参考这个

3. 修改错误界面指向(网上多流传这种方式,但是没有改变请求方法,所以行不通,所以采用以下方法),代码如下:

upstream static_backend {
    server localhost:80;
}

server {
    listen 80;
    error_page 405 =200 @405;
    location @405 {
        root /srv/http;
        proxy_method GET;
        proxy_pass http://static_backend;
    }
}


这个处理的思路是将405的错误信息重新指向一个命名为@405location地址,同时修改请求方式为get方法,这个方法同上面的第一个方法是一样的。这个location将请求重新发送给proxy_pass中定义的static_backendupstream原本是用来配置负载均衡地址的,这里直接给了一个后台访问地址,思路没问题

不过,很不幸的是,上面这些方法中我试过了第一个和第三个,对我没有效果,第二个我就不去试了,我觉得nginx这样的设置肯定是有他的道理的,即使通过修改源码暂时达到了预期的效果,那这样也会带来隐患,难道以后就不升级nginx了吗,是吧,所以我觉得修改源码是最不靠谱的办法。

既然这几个方法都没有效果,那就看看后台服务的日志有没有收到请求,结果发现后台服务启动之后根本就没有收到Nginx 的任何请求转发,也就是说所有的请求(包括get)都没有到达后台,此时我就开始怀疑是location配置的问题,为什么这么说呢,因为如果是普通的405 not allowed异常情况,至少get请求是没有问题的,但是在查看控制台以及后台服务后发现,后台没有接收到请求,而浏览器的控制台中-network一栏,get请求的respone是一个静态页面,也并不是预想中的json数据,如下:

而在Headers一栏显示请求是OK的,如下:

根据这个情况我更加确定,这个问题并不是它表现出来的 405 not allowed,很有可能是由于 location配置异常导致了 405 not allowed,顺着这个思路我又复习了location的配置,我原来的location 配置如下:

location = /demo {
      # rewrite  ^.+demo/?(.*)$ /$1 break;
      proxy_pass  http://localhost:19998;
      proxy_set_header Host $host:$proxy_port;
      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_read_timeout         90;
      proxy_buffer_size          4k;
      proxy_buffers              4 32k;
      proxy_busy_buffers_size    64k;
      proxy_temp_file_write_size 64k;
    }
	
location / {
      root /home/jenkins/workspace/demo-2.0/dist;
      try_files $uri $uri/ /index.html;
      proxy_redirect http:// https://;
      proxy_set_header Upgrade $http_upgrade;
      proxy_set_header Connection "upgrade";
     }

这是一个严格匹配模式,在location中有3中匹配模式,参考这个,分别是:

  • location = patt {} [精准匹配]
  • location patt{} [普通匹配]
  • location ~ patt{} [正则匹配]

其中精准匹配的优先级最高 --> 普通匹配 --> 正则匹配。

问题解决

我将location = /demo {}修改成了location /demo {}就解决了问题,为什么呢?

个人理解,精准匹配是需要指定到具体某一个访问资源的,比如:location = /demo/index.html,应该这样写才对,我的post请求中请求的url地址是一个很长串的地址,比如:localhost:19999/demo/user/query 这种,所以其实根本就没有匹配到 /demo,而是匹配到了最下面的 location / {}这里,所以请求全都被发送到了主页面上,导致nginx判断所有的请求都是在请求一个index.html,这违反了nginx的设计原则,即:不允许静态文件响应POST请求,所以才出现了***404 not allowed*** 的异常。

解决这个问题的同时又复习了nginx的配置知识点,真是收获很多,感谢万能的网友。

参考资料: 链接1 链接2 链接3 链接4 链接5 链接6 链接7

转载于:https://my.oschina.net/u/4118973/blog/3097428

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值