【问题标题】:Jersey Client: Adding Cookies to RequestJersey 客户端:向请求添加 Cookie
【发布时间】:2020-07-04 05:44:52
【问题描述】:

我正在尝试编写一个使用 Jersey 客户端 API 访问 RESTful Web 服务的库。该服务需要一个设置 cookie 的登录请求,然后后续请求必须设置该 cookie 才能成功。登录请求按预期工作,我能够在登录响应中检索 cookie,但似乎无法在后续请求中重新添加 cookie。谁能告诉我可能做错了什么。这是发出请求的代码:

MultivaluedMap<String,String> qs = new MultivaluedMapImpl();
qs.add( "xml", this.toXmlString() );

WebResource wr = client.resource( Constants.ServiceURL );    
if ( CookieJar.Cookies != null )
{
  for ( NewCookie c : CookieJar.Cookies )
  {
    logger.debug( "Setting cookie " + c.getName() );
    wr.cookie( c );
  }
}

ClientResponse response = wr.queryParams( qs ).get( ClientResponse.class );

虽然请求没有失败,但服务会响应应用程序错误“No Session”。这是请求序列的日志跟踪:

Jul 15, 2011 5:20:33 PM com.sun.jersey.api.client.filter.LoggingFilter log
INFO: 1 * Client out-bound request
1 > GET https://www.company.com/TrackerXMLInterface.asp?xml=%3Cxml%3E%3CTRANTYPE%3ELOGIN%3C/TRANTYPE%3E%3CTRANPARMS%3E%3CLOGINID%3Emylogin%3C/LOGINID%3E%3CPASSPHRASE%3EBa1b2c3%3C/PASSPHRASE%3E%3C/TRANPARMS%3E%3C/xml%3E

Jul 15, 2011 5:20:35 PM com.sun.jersey.api.client.filter.LoggingFilter log
INFO: 1 * Client in-bound response
1 < 200
1 < Date: Fri, 15 Jul 2011 22:20:35 GMT
1 < Content-Length: 150
1 < Set-Cookie: ASPSESSIONIDSUBSBSRR=GBGOKGJDAAHCNDDHPBFICFIH; secure; path=/
1 < Content-Type: text/html
1 < Server: Microsoft-IIS/7.0
1 < X-Powered-By: ASP.NET
1 < Cache-Control: private
1 < 
<XML><TRANRESULTS><TRANRETURNCODE>L00</TRANRETURNCODE><TRANRETURNMSG>Valid Login         </TRANRETURNMSG><TRANDETAIL></TRANDETAIL></TRANRESULTS></XML>
[continued below]

我认为以下请求的标头中应该包含 cookie:

Jul 15, 2011 5:20:35 PM com.sun.jersey.api.client.filter.LoggingFilter log
INFO: 1 * Client out-bound request
1 > GET https://www.company.com/TrackerXMLInterface.asp?xml=%3Cxml%3E%3CTRANTYPE%3ESSNLAST%3C/TRANTYPE%3E%3CTRANPARMS%3E%3CSSN%3E123456789%3C/SSN%3E%3CLASTNAME%3ESchmoe%3C/LASTNAME%3E%3C/TRANPARMS%3E%3C/xml%3E

Jul 15, 2011 5:20:35 PM com.sun.jersey.api.client.filter.LoggingFilter log
INFO: 1 * Client in-bound response
1 < 200
1 < Date: Fri, 15 Jul 2011 22:20:35 GMT
1 < Content-Length: 150
1 < Set-Cookie: ASPSESSIONIDSUBSBSRR=HBGOKGJDIAPBBEIGLOILDJDN; secure; path=/
1 < Content-Type: text/html
1 < Server: Microsoft-IIS/7.0
1 < X-Powered-By: ASP.NET
1 < Cache-Control: private
1 < 
<XML><TRANRESULTS><TRANRETURNCODE>R04</TRANRETURNCODE><TRANRETURNMSG>No Session          </TRANRETURNMSG><TRANDETAIL></TRANDETAIL></TRANRESULTS></XML>

非常感谢任何有关这方面的指导。

【问题讨论】:

    标签: java rest jersey


    【解决方案1】:

    问题是 WebResource 是不可变的 - cookie() 方法返回 WebResource.Builder。因此,执行以下操作只会在您每次调用 cookie 时创建一个新的 WebResource.Builder 实例(并且根本不会修改原始 WebResource)。您忽略那些 Builder 实例并仍然在原始 WebResource 上执行请求:

    for ( NewCookie c : CookieJar.Cookies ) {
        logger.debug( "Setting cookie " + c.getName() );
        wr.cookie( c );
    }
    

    您应该改为:

    WebResource.Builder builder = wr.getRequestBuilder();
    for (NewCookie c : CookieJar.Cookies) {
        builder = builder.cookie(c);
    }
    

    然后您可以通过以下方式提出请求:

    ClientResponse response = builder.queryParams(qs).get(ClientResponse.class);
    

    另外,为避免在所有资源方法中重复此代码,您可能需要考虑编写一个客户端过滤器,它会为您处理所有请求。例如。以下代码将确保为每个响应设置从服务器发送的 cookie:

    client.addFilter(new ClientFilter() {
        private ArrayList<Object> cookies;
    
        @Override
        public ClientResponse handle(ClientRequest request) throws ClientHandlerException {
            if (cookies != null) {
                request.getHeaders().put("Cookie", cookies);
            }
            ClientResponse response = getNext().handle(request);
            if (response.getCookies() != null) {
                if (cookies == null) {
                    cookies = new ArrayList<Object>();
                }
                // simple addAll just for illustration (should probably check for duplicates and expired cookies)
                cookies.addAll(response.getCookies());
            }
            return response;
        }
    });
    

    注意:这仅在您不与多个线程共享客户端实例时才有效!

    【讨论】:

      【解决方案2】:

      我发现确保发送回 cookie 的更简单方法是使用 jersey-client 的 Apache HTTP 客户端集成。它在maven包jersey-apache-client中找到:

      <dependency>
        <groupId>com.sun.jersey.contribs</groupId>
        <artifactId>jersey-apache-client</artifactId>
        <version>1.13</version>
        <type>jar</type>
      </dependency>
      

      你可以这样做:

      ApacheHttpClientConfig config = new DefaultApacheHttpClientConfig();
      config.getProperties().put(ApacheHttpClientConfig.PROPERTY_HANDLE_COOKIES, true);
      ApacheHttpClient client = ApacheHttpClient.create(config);
      

      从那时起,只要在请求中继续使用同一个客户端,cookie 就会被收集并按预期发送回服务器。

      【讨论】:

      • 看起来这种方法只与 Jersey v1 兼容
      • @harschware 检查我对 Jersey v2 等价物的回答
      【解决方案3】:

      也许您需要将 cookie 放入之前在没有它们的情况下可以正常工作的 WebResource 调用中。然后,您可能会发现自己破坏了您可以与构建器一起工作的代码行。要包含 cookie,您的代码可能来自:

      clientResponse =   webResource.queryParams(parameters).type(httpContentType).accept(httpAcceptType).post(ClientResponse.class, requestBody);
      

      收件人:

      builder = webResource.queryParams(parameters).type(httpContentType);
      if (cookieJar != null)
      {
          for (Cookie c : cookieJar)
              builder = builder.cookie(c);
      }
      clientResponse = builder.accept(httpAcceptType).post(ClientResponse.class, requestBody);
      

      【讨论】:

        【解决方案4】:

        这是@Emmanuel Touzery 的答案的球衣 v2 等价物:

        import org.glassfish.jersey.apache.connector.ApacheClientProperties;
        import org.glassfish.jersey.apache.connector.ApacheConnectorProvider;
        ...
        
        ...
        ClientConfig config = new ClientConfig();
        config.connectorProvider(new ApacheConnectorProvider());
        config.property(ApacheClientProperties.DISABLE_COOKIES, false);
        client = ClientBuilder.newClient(config);
        

        【讨论】:

          猜你喜欢
          • 2016-06-15
          • 1970-01-01
          • 2015-05-17
          • 1970-01-01
          • 2020-01-24
          • 1970-01-01
          • 2014-04-16
          • 1970-01-01
          • 2010-11-14
          相关资源
          最近更新 更多