Джерси-клиент: добавление файлов cookie для запроса
Я пытаюсь написать библиотеку, которая обращается к веб-службе RESTful, используя API-интерфейс Jersey Client. Для службы требуется запрос на вход, который устанавливает 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 );
Пока запрос не прерывается, служба отвечает приложением "Нет сеанса". Вот трассировка журнала последовательности запросов:
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>
Любые рекомендации по этому поводу очень ценятся.
Ответы
Ответ 1
Проблема заключается в том, что WebResource неизменен - метод cookie() возвращает WebResource.Builder. Таким образом, выполнение следующего просто создает новый экземпляр WebResource.Builder каждый раз, когда вы вызываете cookie (и вообще не изменяете оригинальный 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;
}
});
ПРИМЕЧАНИЕ. Это будет работать, только если вы не используете экземпляры клиентов с несколькими потоками!
Ответ 2
Я обнаружил, что более простой способ гарантировать, что файлы cookie отправляются обратно, - это использование клиентской интеграции Apache HTTP jersey-client. Он найден в пакете jersey-apache-клиента maven:
<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 будут собраны и отправлены обратно на сервер, как ожидалось.
Ответ 3
Возможно, вам нужно поместить файлы cookie в вызов WebResource, который ранее работал без них. Тогда вы, возможно, обнаружите, что разбиваете свою линию кода, с которой вы можете частично работать со строителем. Чтобы включить файлы cookie, ваш код может перейти от:
clientResponse = webResource.queryParams(parameters).type(httpContentType).accept(httpAcceptType).post(ClientResponse.class, requestBody);
To:
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);