OkHTTP Post错误405但是curl命令正常

问题描述

最近我尝试在服务上用OkHttp向"IP_Address/playlists"发送post请求的时候,收到了错误405。错误信息为:

192.168.0.105 - - [19/Jul/2018 17:23:37] "POST //playlists HTTP/1.1" 405 -

来自服务器的响应为:

Allow: HEAD, GET, OPTIONS Content-Length: 178 Server: Werkzeug/0.14.1 Python/3.7.0 Date: Fri, 20 Jul 2018 01:57:56 GMT <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"> <title>405 Method Not Allowed</title> <h1>Method Not Allowed</h1> <p>The method is not allowed for the requested URL.</p>

但是我用curl命令发送相同的httppost请求,却得到的是成功的响应。

在对Okhttp做了多次正确性验证后,实在还是一头雾水

问题解决

在对响应结果做打印追踪问题时,找到了它要访问的完整URL是"http://IP_Address_Another/playlists",于是将要访问的url直接改成"http://IP_Address_Another/playlists"就好了

问题分析

在网上查找405问题期间,发现了有以下几个结论:

  1. POST类请求出现302跳转,302跳转的时候会更改请求方法此时服务端可能不能识别,则报405错误。
  2. 请求服务端直接校验Method,对应Response Header中会有Allow =GET的信息字样。
  3. 负载均衡或者Web Server上做转发的时候,修改了请求Method导致后端无法识别。
  4. 重定向的时候有"Violate RFC 2616/10.3.2 and switch from POST to GET",从POST转到了Get

对于本次问题进行分析,考虑到应该是第一种和第四种的结合,用curl -v试验了一下,果然中间走了一层3xx。在重定向的时候,发现有verbose是"Violate RFC 2616/10.3.2 and switch from POST to GET",curl命令默认是不做POST转GET,而okHttp是做了中转的。

知识拓展:Okhttp重定向处理

重定向

客户端向服务器发送一个请求,获取对应的资源,服务器收到请求后,发现请求的这个资源实际放在另一个位置,于是服务器在返回的响应头的Location字段中写入那个请求资源的正确的URL,并设置reponse的状态码为30x 。

相关状态码说明

 

Okhttp代码中的实现

RetryAndFollowUpInterceptorintercept方法中构建了while (true)循环,根据response重建requestRequest followUp = followUpRequest(response)

判断是否需要重定向的逻辑在followUpRequest方法中:

1.如果响应码是307 或者308并且请求方法不是 GET 或者 HEAD 请求不进行重定向。
2.重定向的地址从响应头中获取 “Location”。
3.HTTPS 和 HTTP 之间的重定向,需要根据配置 followSslRedirects 来判断。final boolean followSslRedirects; //安全套接层重定向
4.如果请求不是PROPFIND的重定向,重定向后的请求会转为GET请求。

我们项目中的请求大都是POST请求或者GET请求,有时候为了安全考虑,全部都用POST请求,在遇到重定向的时候会被转成GET请求,或者我们的重定向状态码使用的是307,并且请求方法是GET,Okhttp就不支持了。这就不符合我们的要求了。有时候还可能实现跨域重定向,如:HTTP -> HTTPS。

既然Okhttp默认的实现不能满足我们的要求,就需要我们自己去实现,其实实现很简单,我们只需要自定义一个拦截器,判断重定向的响应码,然后从响应头中获取重定向后的地址,重新请求一遍即可。

重定向处理

 1 //处理重定向的拦截器
 2 public class RedirectInterceptor implements Interceptor {
 3 
 4     @Override
 5     public Response intercept(Chain chain) throws IOException {
 6         okhttp3.Request request = chain.request();
 7         Response response = chain.proceed(request);
 8         int code = response.code();
 9         if (code == 307) {
10             //获取重定向的地址
11             String location = response.headers().get("Location");
12             LogUtils.e("重定向地址:", "location = " + location);
13             //重新构建请求
14             Request newRequest = request.newBuilder().url(location).build();
15             response = chain.proceed(newRequest);
16         }
17         return response;
18     }
19 }
20 
21  //使用
22  OkHttpClient client = new OkHttpClient.Builder()
23                     .followRedirects(false);  //禁制OkHttp的重定向操作,我们自己处理重定向
24                     .addInterceptor(new RedirectInterceptor())
25                     .build();

 

参考:https://forge.etsi.org/rep/cyber/103523_MSP/tlmsp/tlmsp-curl/-/blob/0b516b7162dc387ed80b0f24476b950ab2e18cb7/include/curl/curl.h

参考:https://www.jianshu.com/p/f2b287a176f5

posted @ 2022-09-15 20:24  Boblim  阅读(877)  评论(0编辑  收藏  举报