HTTP中间层不支持PUT/DELETE等特定METHOD时的处理

鉴于很多兄弟有问题,特意在文章顶部小结一下nginx使用:

  • nginx里配置,在server配置里,或location的配置里,添加如下配置,并重启nginx:
    set $method $request_method;
    proxy_set_header X-Old-Method $request_method; # 测试用
    if ($http_X_HTTP_Method_Override ~* 'PUT|DELETE') { # 也可以改成if ($http_X_HTTP_Method_Override) 这是强制替换
        set $method $http_X_HTTP_Method_Override;
    }
    proxy_method $method;
  • 在请求的header里添加 X-HTTP-Method-Override: PUT
  • 注意:
    • nginx配置使用下划线$http_X_HTTP_Method_Override,请求使用横杠X-HTTP-Method-Override
    • nginx默认会忽略带下划线的header名,所以请求的header名如果带下划线,nginx是收不到的
    • 按rfc标准,header名忽略大小写,因此X-HTTP-Method-Override等同于x-http-method-override
      • 注:header的值是大小写敏感的,url也是大小写敏感的,METHOD是必须大写的

原文如下:
昨天,有兄弟跑过来找我,说正在开发的支付宝小程序,只支持HTTP协议里的GET和POST请求,不支持PUT/DELETE请求!?!?
我们的很多线上服务都已经是按restful设计,有PUT和DELETE的api,总不可能让这些服务都为了支付宝,适配一堆POST的api吧?这个工作量不说,后续的维护以及新功能开发,都存在麻烦!暂时不考虑这种方案!

这时,一个同事说有一个扩展属性:X-HTTP-Method-Override,它是一个非标准的HTTP协议头,是约定俗成的一个请求头字段,用于规避上面这种问题,举个例子:

一个正常的请求是:
DELETE http://cc.beinet.com/api/code HTTP/1.1
Host: cc.beinet.com
Content-Length: 6
User-Agent: Mozilla/5.0
Content-Type: application/json

para=1

我们要改成===注意第一行变成了POST

POST http://cc.beinet.com/api/code HTTP/1.1
Host: cc.beinet.com
Content-Length: 6
User-Agent: Mozilla/5.0
Content-Type: application/json
X-HTTP-Method-Override: DELETE

para=1

OK, 为绕过支付宝的问题,我们需要做如下2步:

1、前端必须改代码,这个无法绕过,所有的PUT/DELETE请求,都要求改成POST;
  所有的PUT请求,要携带Header:X-HTTP-Method-Override: PUT
  所有的DELETE请求,要携带Header:X-HTTP-Method-Override: DELETE
注:有兄弟问我,能不能不用POST,改用GET,答案是不可以,因为在RFC2616-HTTP协议里,不建议在GET请求带上body数据,很多的HTTP服务也不支持GET请求带body,比如google就会报400错误,测试命令:
curl -X GET https://www.google.com -d "{Id: 0}"

2、服务端根据Header:X-HTTP-Method-Override,转换请求METHOD
  2.1、在nginx层修改和转发,服务端不需要做任何处理即可,参考配置:

server {
    listen       443 ssl http2;
    server_name  cc.beinet.com;
    access_log /data/logs/nginx/cc.beinet.com.log main;
    # 在你的nginx配置里,添加下面5行,记得执行 nginx -s reload 重新加载
    set $method $request_method;
    if ($http_X_HTTP_Method_Override ~* 'PUT|DELETE') {
        set $method $http_X_HTTP_Method_Override;
    }
    proxy_method $method;

    location / {
        root /data/wwwroot/html;
    }

2.2、如果你们没有nginx,那只能修改服务端代码了,Asp.net WebApi参考修改方案:   https://www.hanselman.com/blog/HTTPPUTOrDELETENotAllowedUseXHTTPMethodOverrideForYourRESTServiceWithASPNETWebAPI.aspx

// 项目中添加这个类
public class MethodOverrideHandler : DelegatingHandler
{
    readonly string[] _methods = { "DELETE", "HEAD", "PUT" };
    const string _header = "X-HTTP-Method-Override";
    protected override Task<HttpResponseMessage> SendAsync(
        HttpRequestMessage request, CancellationToken cancellationToken)
    {
        if (request.Method == HttpMethod.Post && request.Headers.Contains(_header))
        {
            var method = request.Headers.GetValues(_header).FirstOrDefault();
            if (_methods.Contains(method))
            {
                request.Method = new HttpMethod(method);
            }
        }
        return base.SendAsync(request, cancellationToken);
    }
}

// 然后在你的WebApi项目的global.asax.cs里添加如下代码:
protected void Application_Start()
{
    GlobalConfiguration.Configuration.MessageHandlers.Add(new MethodOverrideHandler());

好了,服务端的2个方案,你任意使用其中一个,即可解决问题,测试方法,可以用curl验证,用如下2个命令,如果返回结果一致,说明修改成功生效:

curl -X PUT  -H "Content-Type: application/json" -d "{Id: 0}" http://你的域名/api/xxx

curl -X POST -H "Content-Type: application/json" -d "{Id: 0}" http://你的域名/api/xxx -H "X-HTTP-Method-Override: PUT"

btw: 我公司的兄弟,在实际上线中,还碰到了别的问题,原因是他把POST写成小写的post了,这是不符合http协议标准的,标准里强制所有METHOD必须大写,参考:
https://tools.ietf.org/html/rfc2616#section-5.1.1

5.1.1 Method

   The Method  token indicates the method to be performed on the
   resource identified by the Request-URI. The method is case-sensitive.
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

游北亮

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值