2011-07-15 163 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