当我们的Android客户端使用Apache HTTP客户端向我们的服务器发出请求时,我希望它使用相同的HTTP方法重定向到新的URL(或更具体的,其他上下文路径)。
在我的httpd.conf中,我使用状态代码307来配置此规则:
Redirect 307 /mybipper/reg /mybipperapi/old/reg
根据维基百科中的状态码描述,307应该:
http://en.wikipedia.org/wiki/HTTP_307#3xx_Redirection
307临时重定向(自HTTP / 1.1起) 在这种情况下,请求应该使用另一个URI重复;但是,未来的请求仍然可以使用原始URI。[2]与历史上实现302的方式相反,在重新发出原始请求时不应更改请求方法。例如,必须使用另一个POST请求重复POST请求。
但在我的访问日志中,我们看到HTTP客户端似乎不尊重它并执行GET,就像我返回状态代码302
172.29.9.120 - - [21/Sep/2012:14:02:11 +0300] "POST /mybipper/reg HTTP/1.1" 307 248
172.29.9.120 - - [21/Sep/2012:14:02:11 +0300] "GET /mybipperapi/old/reg HTTP/1.1" 400 1016
根据Apache HTTP Client网站,它有点不清楚它应该如何处理状态代码307,但它们至少在那里列出它。
http://hc.apache.org/httpclient-3.x/redirects.html
我非常感觉它的Apache HTTP客户端没有正确实现HTTP 1.1协议,我是正确的还是我误解了什么?
我们使用的Apache HTTP客户端与Android SDK捆绑在一起。我正在测试的手机上安装了Android SDK 15,正是这个:
http://developer.android.com/about/versions/android-4.0.3.html
答案 0 :(得分:4)
DefaultRedirectStrategy
仅允许自动重定向GET和HEAD。如果您还想允许POST(但不允许PUT或DELETE),您可以通过执行以下操作切换到LaxRedirectStrategy
:
HttpClientBuilder hcb = HttpClients.custom();
hcb.setRedirectStrategy(new LaxRedirectStrategy());
HttpClient client = hcb.build();
如果你想跟随PUT和DELETE(就像我们这里一样),你将不得不实现一个自定义策略(注意:我们遇到了HttpClient中的一个错误,它似乎试图添加第二个内容-Length标题,当我们这样做,所以我们手动删除它.YMMV)。通过使用这种策略,HttpClient还将支持308重定向,这是Apache团队甚至无法包含的内容。
您可以这样做:
hcb.setRedirectStrategy(new DefaultRedirectStrategy() {
public boolean isRedirected(HttpRequest request, HttpResponse response, HttpContext context) throws ProtocolException {
Args.notNull(request, "HTTP request");
Args.notNull(response, "HTTP response");
int statusCode = response.getStatusLine().getStatusCode();
switch(statusCode) {
case 301:
case 307:
case 302:
case 308:
case 303:
return true;
case 304:
case 305:
case 306:
default:
return false;
}
}
public HttpUriRequest getRedirect(HttpRequest request, HttpResponse response, HttpContext context) throws ProtocolException {
URI uri = this.getLocationURI(request, response, context);
String method = request.getRequestLine().getMethod();
if(method.equalsIgnoreCase("HEAD")) {
return new HttpHead(uri);
} else if(method.equalsIgnoreCase("GET")) {
return new HttpGet(uri);
} else {
int status = response.getStatusLine().getStatusCode();
HttpUriRequest toReturn = null;
if(status == 307 || status == 308) {
toReturn = RequestBuilder.copy(request).setUri(uri).build();
toReturn.removeHeaders("Content-Length"); //Workaround for an apparent bug in HttpClient
} else {
toReturn = new HttpGet(uri);
}
return toReturn;
}
}
});
答案 1 :(得分:0)
要扩展Cody的正确答案-如果您需要遵循PUT(或任何其他方法)307重定向,则可以选择扩展LaxRedirectStrategy
,这更加容易:
hcb.setRedirectStrategy(new LaxRedirectStrategy()
{
protected boolean isRedirectable(String method)
{
return "PUT".equalsIgnoreCase(method)||super.isRedirectable(method);
}
});
但是,这也不能解决以下308错误的问题。我知道这是一个老问题,但直到今天我也遇到了同样的问题(感谢科迪)。
答案 2 :(得分:0)
如果您还要向LaxRedirectStrategy添加308,请参见下面的代码
.setRedirectStrategy(new LaxRedirectStrategy() {
@Override
public boolean isRedirected(
final HttpRequest request,
final HttpResponse response,
final HttpContext context) throws ProtocolException {
Args.notNull(request, "HTTP request");
Args.notNull(response, "HTTP response");
final int statusCode = response.getStatusLine().getStatusCode();
final String method = request.getRequestLine().getMethod();
final Header locationHeader = response.getFirstHeader("location");
switch (statusCode) {
case HttpStatus.SC_MOVED_TEMPORARILY:
return isRedirectable(method) && locationHeader != null;
case HttpStatus.SC_MOVED_PERMANENTLY:
case HttpStatus.SC_TEMPORARY_REDIRECT:
return isRedirectable(method);
case HttpStatus.SC_SEE_OTHER:
return true;
case 308:
return true;
default:
return false;
} //end of switch
}
})
.build();```