我正在尝试编写一个使用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>
非常感谢对此的任何指导。
问题是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; } });
注意:仅当您不共享具有多个线程的客户端实例时,这才有效!