泽西客户:向请求添加Cookie

时间:2011-07-15 22:37:11

标签: java rest jersey

我正在尝试编写一个使用Jersey Client 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>

非常感谢任何关于此的指导。

4 个答案:

答案 0 :(得分:24)

问题是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;
    }
});

注意:只有在不与多个线程共享客户端实例时才会这样做!

答案 1 :(得分:9)

我发现确保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并按预期将其发送回服务器。

答案 2 :(得分: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);

答案 3 :(得分:1)

这是@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);