Заголовок Content-Length уже присутствует - PullRequest
29 голосов
/ 26 июля 2010

Я использую Apache HttpClient (4.1), включенный в Android, для выполнения HttpPut.Я подтвердил, что у меня есть только один заголовок с длиной содержимого.Однако каждый раз, когда я отправляю запрос, я получаю исключение протокола относительно уже указанного заголовка Content-Length.

HttpClient client = new DefaultHttpClient();
putMethod = new HttpPut(url + encodedFileName);
putMethod.addHeader(..)  //<-once for each header
putMethod.setEntity(new ByteArrayEntity(data));
client.execute(putMethod);  //throws Exception

Причина: org.apache.http.ProtocolException: заголовок Content-Length уже присутствует вorg.apache.http.protocol.RequestContent.process (RequestContent.java:70) в org.apache.http.protocol.BasicHttpProcessor.process (BasicHttpProcessor.java:290)

Есть идеи?

Ответы [ 6 ]

31 голосов
/ 11 марта 2015

Как указывает igor.zh, эта проблема может возникать при использовании класса Spring HttpComponentsMessageSender. Точнее, это проблема, только если вы передаете свой собственный экземпляр HttpClient в конструктор HttpComponentsMessageSender - в противном случае проблема обрабатывается автоматически.

Начиная с spring-ws 2.1.4, подкласс HttpComponentsMessageSender.RemoveSoapHeadersInterceptor, который используется в конструкторе по умолчанию, был открыт для решения этой проблемы (см. https://jira.spring.io/browse/SWS-835) и поэтому может использоваться вместо этого в ваших собственных экземплярах HttpClient написания собственного класса для этого. Он также очищает заголовок HTTP.TRANSFER_ENCODING.

Используйте метод HttpClientBuilder.addInterceptorFirst, чтобы внедрить этот перехватчик в ваш собственный экземпляр HttpClient. Пример ниже с использованием проводки XML bean. Если кто-нибудь знает более краткий способ создания экземпляра HttpClient (кроме написания класса фабричного компонента), я весь в ушах!

<bean id="httpClientBuilder" class="org.apache.http.impl.client.HttpClientBuilder" factory-method="create"/>

<bean id="interceptedHttpClientBuilder" class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
    <property name="targetObject" ref="httpClientBuilder" />
    <property name="targetMethod" value="addInterceptorFirst"> </property>
    <property name="arguments">
        <list>
            <bean class="org.springframework.ws.transport.http.HttpComponentsMessageSender.RemoveSoapHeadersInterceptor"/>
        </list>
    </property>
</bean>

<bean id="httpClient" factory-bean="interceptedHttpClientBuilder" factory-method="build" />

<bean id="webServiceTemplate" class="org.springframework.ws.client.core.WebServiceTemplate">
    <constructor-arg ref="messageFactory"/>
    <property name="messageSender">
        <bean class="org.springframework.ws.transport.http.HttpComponentsMessageSender">
            <property name="httpClient" ref="httpClient"/>
        </bean>
    </property>
</bean>

В качестве альтернативы, если вы можете, просто разрешите HttpComponentsMessageSender создать свой собственный экземпляр HttpClient, а не передавать его ему. Небольшое замечание по этому поводу: начиная с spring-ws 2.2.0-RELEASE, конструктор по умолчанию для HttpComponentsMessageSender продолжает использовать класс DefaultHttpClient, который теперь устарел. Надеюсь, это будет исправлено в следующем выпуске.

29 голосов
/ 26 июля 2010

Я сам не использовал HttpClient, но подозреваю, что проблема в том, что putMethod.setEntity(...) неявно предоставляет длину контента, и вы также устанавливаете ее явно с помощью одного из вызовов putMethod.addHeader(...).

13 голосов
/ 06 июня 2014

Это происходит со мной, когда я использовал http://docs.spring.io/spring-ws/site/apidocs/org/springframework/ws/transport/http/HttpComponentsMessageSender.html в качестве отправителя сообщения Spring WebService.В этом случае такие вещи, как HttpPut или HttpRequest, не легко доступны, поэтому, создав HttpClient с помощью HttpClientBuilder, я в итоге вставил HttpRequestInterceptor перед виновником RequestContent:

private static class ContentLengthHeaderRemover implements HttpRequestInterceptor{
    @Override
    public void process(HttpRequest request, HttpContext context) throws HttpException, IOException {
        request.removeHeaders(HTTP.CONTENT_LEN);// fighting org.apache.http.protocol.RequestContent's ProtocolException("Content-Length header already present");
    }
}
...
    HttpClientBuilder httpClientBuilder = HttpClients.custom();
    httpClientBuilder.addInterceptorFirst(new CcontentLengthHeaderRemover());
3 голосов
/ 12 июля 2017

Ответ Джона Рикса имеет правильную идею.Вот как вы делаете это с простой Java:

HttpClient client = HttpClients.custom()
    .addInterceptorFirst(new RemoveSoapHeadersInterceptor())
    .build();
1 голос
/ 18 мая 2011

Если вы оформите заказ http://docjar.org/docs/api/org/apache/http/protocol/RequestContent.html, вы заметите, что оно выдает это исключение, если вы установили его самостоятельно. Поэтому внутренние рабочие задают длину контента автоматически. Это также означает, что для установки значения «0» необходимо установить для объекта значение null.

0 голосов
/ 15 февраля 2019

@ ответ Джона Рикса Этот код помог решить проблему

    private static class ContentLengthHeaderRemover implements HttpRequestInterceptor{
            @Override
            public void process(HttpRequest request, HttpContext context) throws HttpException, IOException {
                request.removeHeaders(HTTP.CONTENT_LEN);// fighting org.apache.http.protocol.RequestContent's ProtocolException("Content-Length header already present");
            }
        }
HttpClient client = HttpClients.custom()
                .addInterceptorFirst(new ContentLengthHeaderRemover())
                .build();
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...