HttpClient下完美Post/Redirect/Post

一些特殊的原因,需要利用HttpClient自动的完成Post方法的301重定向,看了默认HttpClient官方给出的默认实现是org.apache.http.impl.client.DefaultRedirectStrategy,可以定向的方法就限定死了,

/**
 * Redirectable methods.
 */
private static final String[] REDIRECT_METHODS = new String[] {
    HttpGet.METHOD_NAME,
    HttpHead.METHOD_NAME
};

显然是无法完成Post/Redirect/Post的,所以还得继续找Apache针对接口org.apache.http.client.RedirectStrategy的实现,还好在IDE的帮助下很快找到了这个Apache关于自动重定向的终极实现org.apache.http.impl.client.LaxRedirectStrategy,这回支持Post的重定向了,但是发现无法将原Post请求Body中的数据传递下去直接丢失了,这显然是非常不理想的,无法保持原有请求的完整性几乎等于白做一样。苦恼之下只能自行实现RedirectStrategy接口,不过可以继承DefaultRedirectStrategy覆盖他的isRedirectedgetRedirect,实现关键的获取重定向后的HttpUriRequest即可,即:

    @Override
    public HttpUriRequest getRedirect(HttpRequest request, HttpResponse response, HttpContext context) throws ProtocolException {

    }

看了HttpRequest 的接口后瞬间就麻木了,

public interface HttpRequest extends HttpMessage {

    RequestLine getRequestLine();
    ProtocolVersion getProtocolVersion();
    boolean containsHeader(String name);
    Header[] getHeaders(String name);
    Header getFirstHeader(String name);
    Header getLastHeader(String name);
    Header[] getAllHeaders();
    void addHeader(Header header);
    void addHeader(String name, String value);
    void setHeader(Header header);
    void setHeader(String name, String value);
    void setHeaders(Header[] headers);
    void removeHeader(Header header);
    void removeHeaders(String name);
    HeaderIterator headerIterator();
    HeaderIterator headerIterator(String name);
    HttpParams getParams();
    void setParams(HttpParams params);

}

我擦这TM怎么拿到原有请求数据重新封装啊?就算不给拿原有请求数据接口,给个重置URI的接口行不?查找各种官方资料,毛介绍说明都没有,啥都不行,走到这一步完全不知该如何搞了。
再次苦恼后并怀着对HttpClient团队的深深的不理解,开始尝试着利用反射机制把request和context都打印出来看看,看看这两货里面有没有我想要的东西

uir : https://t.xx.com/xxxxxx,

context : org.apache.http.client.protocol.HttpClientContext@3d04562f[context={http.cookie-origin=[t.xx.com:80/xxxxxx], http.auth.credentials-provider={}, http.connection=CPoolProxy{127.0.0.1:44087<->127.0.0.1:80}, http.response=HttpResponseProxy{HTTP/1.1 301 Moved Permanently [Server: nginx/1.7.1, Date: Thu, 30 Jul 2015 12:09:29 GMT, Content-Type: text/html, Content-Length: 184, Connection: keep-alive, Location: https://t.xx.com/xxxxxx]}, http.target_host=http://t.xx.com:80, http.protocol.redirect-locations=[https://t.xx.com/xxxxxx], http.cookie-spec=best-match, http.cookiespec-registry={ignorecookies=org.apache.http.impl.cookie.IgnoreSpecFactory@1815b417, rfc2109=org.apache.http.impl.cookie.RFC2109SpecFactory@38e25e5b, rfc2965=org.apache.http.impl.cookie.RFC2965SpecFactory@15a0c58a, compatibility=org.apache.http.impl.cookie.BrowserCompatSpecFactory@6e08f21d, standard=org.apache.http.impl.cookie.RFC2965SpecFactory@d4f865b, best-match=org.apache.http.impl.cookie.BestMatchSpecFactory@5ffdc730, netscape=org.apache.http.impl.cookie.NetscapeDraftSpecFactory@e20518c}, http.route={}->http://t.xx.com:80, http.request=POST /xxxxxx HTTP/1.1 [Content-Type: application/x-thrift, Accept: application/x-thrift, User-Agent: Java/THttpClient/HC, Content-Length: 48, Host: t.xx.com:80, Connection: Keep-Alive, Accept-Encoding: gzip,deflate], http.cookie-store=[], http.auth.proxy-scope=state:UNCHALLENGED;, http.request_sent=true, http.request-config=, expectContinueEnabled=false, proxy=null, localAddress=null, staleConnectionCheckEnabled=true, cookieSpec=null, redirectsEnabled=true, relativeRedirectsAllowed=true, maxRedirects=50, circularRedirectsAllowed=false, authenticationEnabled=true, targetPreferredAuthSchemes=null, proxyPreferredAuthSchemes=null, connectionRequestTimeout=-1, connectTimeout=10000, socketTimeout=10000], http.auth.target-scope=state:UNCHALLENGED;, http.authscheme-registry={basic=org.apache.http.impl.auth.BasicSchemeFactory@6bc9c592, digest=org.apache.http.impl.auth.DigestSchemeFactory@bca2b87, ntlm=org.apache.http.impl.auth.NTLMSchemeFactory@5efb21d, kerberos=org.apache.http.impl.auth.KerberosSchemeFactory@3b9690f6, negotiate=org.apache.http.impl.auth.SPNegoSchemeFactory@1a07250a}}],

request : org.apache.http.client.methods.HttpRequestWrapper$HttpEntityEnclosingRequestWrapper@4b10c0df[entity=org.apache.http.entity.ByteArrayEntity@1aea9900,original=POST /xxxxxx HTTP/1.1,method=POST,version=HTTP/1.1,uri=/xxxxxx,headergroup=[Content-Type: application/x-thrift, Accept: application/x-thrift, User-Agent: Java/THttpClient/HC, Content-Length: 48, Host: t.xx.com:80, Connection: Keep-Alive, Accept-Encoding: gzip,deflate],params=org.apache.http.params.BasicHttpParams@35d7c7ad]

柳暗花明又一村啊,context没啥有用的信息,但是request的实现类竟然是这货HttpRequestWrapper,属性中竟然还有ByteArrayEntity,这个entity应该就是我们需要的request的body数据体了,还有params,把这些都搞出来传递下去就OK了,开心的去看HttpRequestWrapper接口,关键数据都在封闭的内部类中完全搞不出来,那就换条思路,能修改URI不?惊喜的发现可以。果断实现一个版本,

public class HMRedirectStrategy extends DefaultRedirectStrategy {
    private Logger logger = LoggerFactory.getLogger(getClass());
    @Override
    public boolean isRedirected(HttpRequest request, HttpResponse response, HttpContext context) throws ProtocolException {
        int responseCode = response.getStatusLine().getStatusCode();
        return responseCode == 301 || responseCode == 302;
    }

    @Override
    public HttpUriRequest getRedirect(HttpRequest request, HttpResponse response, HttpContext context) throws ProtocolException {
        URI uri = getLocationURI(request, response, context);
        String method = request.getRequestLine().getMethod();
        if (HttpPost.METHOD_NAME.equalsIgnoreCase(method)){
            try {
                HttpRequestWrapper httpRequestWrapper = (HttpRequestWrapper) request;
                httpRequestWrapper.setURI(uri);
                httpRequestWrapper.removeHeaders("Content-Length");
                return httpRequestWrapper;
            }catch (Exception e){
                logger.error("强转为HttpRequestWrapper出错");
            }
            return new HttpPost(uri);
        }else {
            return new HttpGet(uri);
        }
    }
}

测试后完美实现Post/Redirect/Post。最后吐槽下HttpClient团队,getRedirect这个接口,几乎没有什么有用的说明,只有点象征性的注释,要不是用反射(开发测试过程中也可以用debug来看),鬼能知道HttpRequest的实现类其实是HttpRequestWrapper,本来这些获取基础数据和修改基础数据的接口在这里就应该开放,结果被他们藏的那么深,还搞那么复杂,然后还不给个说明。哎,也真是……(省略若干)
本站地址无极小子,转载注明出处,谢谢。

文章链接:http://www.wanghaomiao.cn/archives/12/ [复制] (转载时请注明本文出处及文章链接)

标签:none

评论已关闭