Jersey 客户端:向请求添加 Cookie

2022-01-21 00:00:00 rest java jersey

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

I am trying to write a library that accesses a RESTful web service using the Jersey Client API. The service requires a login request that sets a cookie, then subsequent requests must have that cookie set to succeed. The login request works as expected, and I am able to retrieve the cookie in the response from the login, but cannot seem to add the cookie back in subsequent requests. Can anyone tell what I might be doing wrong. Here is the code that makes the request:

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".这是请求序列的日志跟踪:

While the request doesn't fail, the service responds with the application error "No Session". Here is the log trace of the request sequence:

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:

I'm thinking the following request should have the cookies in the header:

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>

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

Any guidance on this is much appreciated.

推荐答案

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

The problem is WebResource is immutable - the cookie() method returns WebResource.Builder. So, doing the following just creates a new instance of WebResource.Builder every time you call cookie (and does not modify the original WebResource at all). You ignore those Builder instances and still perform the request on the original 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);
}

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

Then you can make the request by:

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

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

Also, to avoid duplicating this code in all your resource methods, you may want to consider writing a client filter, which will do it for you for all your requests. E.g. the following code would ensure cookies sent from the server get set for each response:

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

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

NOTE: This will only work if you don't share client instances with multiple threads!

相关文章