2011-07-15 73 views
15

我正在尝试编写一个使用Jersey Client API访问RESTful Web服务的库。该服务需要设置cookie的登录请求,然后后续请求必须将该cookie设置为成功。登录请求按预期工作,并且我可以在登录响应中检索到cookie,但似乎无法在随后的请求中添加该cookie。任何人都可以告诉我可能做错了什么。这里是发出请求的代码:Jersey客户端:向请求添加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); 

虽然请求不会失败,服务与应用程序错误“没有会话”响应。这里是请求序列的记录追踪:

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> 

对此有何指导是非常赞赏。

回答

24

问题是WebResource是不可变的 - cookie()方法返回WebResource.Builder。因此,每次调用cookie时(以及根本不修改原始WebResource),只需创建一个新的WebResource.Builder实例即可。你忽略这些生成器实例,仍然执行对原有WebResource请求:

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

你应该这样做,而不是执行以下操作:

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

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

然后你就可以发出请求

此外,为避免在所有资源方法中重复使用此代码,您可能需要考虑编写一个客户端筛选器,该筛选器将为您处理所有请求。例如。下面的代码将确保从服务器发送的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; 
    } 
}); 

注意:这如果不使用多个线程共享客户端实例才起作用!

+1

保存我的测试,谢谢 –

+0

即使在修复后也不适用于我 –

3

也许你需要将cookie放入一个以前没有它们的WebResource调用中。然后你可能会发现自己打破了你可以在构建器中工作的代码行。包括饼干,你的代码可能会去的:

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); 
6

我已经发现,为了确保饼干更简单的方式被发送回是使用jersey-的的Apache HTTP客户端集成客户。它是在Maven包球衣的Apache客户端发现:

<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); 

从那以后,只要继续使用跨请求相同的客户端和饼干将被收集并按预期发回服务器。

+0

看起来像这种方法只能与Jersey v1兼容 – harschware