【解决】HttpClient:org.apache.http.client.protocol.ResponseProcessCookies

错误:

2019-03-02 19:18:53 WARN org.apache.http.client.protocol.ResponseProcessCookies
  - Invalid cookie header: 
"Set-Cookie: FSSBBIl1UgzbN7N80T=111Wl2a.lZ4ICh0
Path=/; expires=Tue, 27 Feb 2029 11:25:09 GMT". 
Invalid 'expires' attribute: Tue, 27 Feb 2029 11:25:09 GMT

通过这个报错,我们可以看出来是因为解析cookie的expires属性导致的解析异常,从而导致HttpContent无法解析出正确的cookie。进入这个类ResponseProcessCookies打一个断点我们就可以定位到问题所在。可以看到网页返回的cookie与期望解析的格式不一致(多了横线),从而导致解析失败的。
在这里插入图片描述
解决办法:
  Ⅰ.重写cookie解析的方法:原文地址

  通过重写DefaultCookieSpec类的parse方法,将EEE, dd MMM yy HH:mm:ss格式的expires转换为EEE, dd-MMM-yy HH:mm:ss格式再交给DefaultCookieSpec来处理。

  Ⅱ.更换解析cookie的格式(推荐此种方法):原文地址RFC文档

  HttpClient实现的cookie解析肯定也是有规范的,这个规范就是RFC文档。HttpClient实现了cookie的多种解析格式,我们可以切换它的解析版本就可以了。如下是Httpclient实现的RFC版本。

//设置CookieSpecs.STANDARD的cookie解析模式,下面为源码,对应解析格式我给出了备注
CloseableHttpClient httpClient= HttpClients.custom()
        .setDefaultRequestConfig(RequestConfig.custom()
                .setCookieSpec(CookieSpecs.STANDARD).build())
        .build();
/**
 * Standard cookie specifications supported by HttpClient.
 *
 * @since 4.3
 */
public final class CookieSpecs {

    /**
     * The policy that provides high degree of compatibility
     * with common cookie management of popular HTTP agents.
     *
     * @deprecated (4.4) use {link #DEFAULT}.
     */
    @Deprecated
    public static final String BROWSER_COMPATIBILITY = "compatibility";

    /**
     * The Netscape cookie draft compliant policy.
     * Wdy, DD-Mon-YY HH:MM:SS GMT
     */
    public static final String NETSCAPE = "netscape";

    /**
     * The RFC 6265 compliant policy (interoprability profile).
     * EEE, dd MMM yyyy HH:mm:ss zzz
     */
    public static final String STANDARD = "standard";

    /**
     * The RFC 6265 compliant policy (strict profile).
     *EEE, dd MMM yyyy HH:mm:ss zzz
     *EEE, dd-MMM-yy HH:mm:ss zzz
     *EEE MMM d HH:mm:ss yyyy
     * @since 4.4
     */
    public static final String STANDARD_STRICT = "standard-strict";

    /**
     * The default 'best match' policy.
     *
     * @deprecated (4.4) use {link #DEFAULT}.
     */
    @Deprecated
    public static final String BEST_MATCH = "best-match";

    /**
     * The default policy. This policy provides a higher degree of compatibility
     * with common cookie management of popular HTTP agents for non-standard
     * (Netscape style) cookies.
     * EEE, dd-MMM-yy HH:mm:ss z
     */
    public static final String DEFAULT = "default";

    /**
     * The policy that ignores cookies.
     * 不解析cookie
     */
    public static final String IGNORE_COOKIES = "ignoreCookies";

    private CookieSpecs() {
    }
}

  • 4
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
好的,以下是一个基于 Apache Commons Pool2 的 Http 连接池实现: 首先,我们需要定义一个 HttpClient 对象的工厂类 PooledHttpClientFactory,它实现了 PooledObjectFactory 接口,负责创建和销毁 HttpClient 对象: ```java import org.apache.commons.pool2.PooledObject; import org.apache.commons.pool2.PooledObjectFactory; import org.apache.commons.pool2.impl.DefaultPooledObject; import org.apache.http.client.HttpClient; import org.apache.http.impl.client.HttpClients; public class PooledHttpClientFactory implements PooledObjectFactory<HttpClient> { @Override public PooledObject<HttpClient> makeObject() throws Exception { HttpClient httpClient = HttpClients.createDefault(); return new DefaultPooledObject<>(httpClient); } @Override public void destroyObject(PooledObject<HttpClient> pooledObject) throws Exception { HttpClient httpClient = pooledObject.getObject(); httpClient.close(); } @Override public boolean validateObject(PooledObject<HttpClient> pooledObject) { return true; } @Override public void activateObject(PooledObject<HttpClient> pooledObject) throws Exception { } @Override public void passivateObject(PooledObject<HttpClient> pooledObject) throws Exception { } } ``` 然后,我们使用 GenericObjectPool 来管理 HttpClient 对象的池: ```java import org.apache.commons.pool2.impl.GenericObjectPool; import org.apache.http.client.HttpClient; public class HttpClientPool { private GenericObjectPool<HttpClient> pool; public HttpClientPool() { PooledHttpClientFactory factory = new PooledHttpClientFactory(); this.pool = new GenericObjectPool<>(factory); } public HttpClient borrowHttpClient() throws Exception { return pool.borrowObject(); } public void returnHttpClient(HttpClient httpClient) { pool.returnObject(httpClient); } } ``` 现在,我们就可以使用 HttpClientPool 来获取 HttpClient 对象了: ```java import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpUriRequest; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClientBuilder; import org.apache.http.message.BasicHeader; import org.apache.http.protocol.BasicHttpContext; import org.apache.http.protocol.HttpContext; import org.apache.http.util.EntityUtils; public class Main { public static void main(String[] args) throws Exception { HttpClientPool httpClientPool = new HttpClientPool(); try (CloseableHttpClient httpClient = HttpClientBuilder.create().build()) { HttpUriRequest httpRequest = new HttpGet("https://www.baidu.com"); HttpContext httpContext = new BasicHttpContext(); httpContext.setAttribute("org.apache.http.client.protocol.HTTPCS", new BasicHeader("Connection", "close")); try (CloseableHttpResponse httpResponse = httpClient.execute(httpRequest, httpContext)) { String responseText = EntityUtils.toString(httpResponse.getEntity()); System.out.println(responseText); } } httpClientPool.returnHttpClient(httpClient); } } ``` 以上就是一个简单的 HttpClient 连接池实现,如果需要更高级的功能,可以参考 Apache HttpClient ConnectionManager 的实现。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值