web-dev-qa-db-ja.com

Content-Lengthヘッダーは既に存在します

Androidに含まれるApache HttpClient(4.1)を使用してHttpPutを実行しています。content-lengthヘッダーが1つしかないことを確認しました。しかし、リクエストを送信するたびに、既に指定されている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)

何か案は?

33
AdamC

私は自分でHttpClientを使用していませんが、問題はputMethod.setEntity(...)が暗黙的にコンテンツの長さを提供しており、putMethod.addHeader(...)呼び出しの1つを介して明示的に設定していることだと思います。

30
Stephen C

Igor.zhで指摘されているように、この問題は、SpringのHttpComponentsMessageSenderクラスを使用している場合に発生する可能性があります。正確には、これはHttpClientの独自のインスタンスをHttpComponentsMessageSenderコンストラクターに渡す場合にのみ問題になります。それ以外の場合、問題は自動的に処理されます。

Spring-ws 2.1.4以降、デフォルトのコンストラクターで使用されるHttpComponentsMessageSender.RemoveSoapHeadersInterceptorサブクラスは、この問題に対処するために公開されました( を参照してください)https://jira.spring.io/browse/SWS-835 )なので、独自のクラスを作成する代わりに、独自のHttpClientインスタンスで使用できます。また、HTTP.TRANSFER_ENCODINGヘッダーもクリアします。

このインターセプターを独自のHttpClientインスタンスに挿入するには、HttpClientBuilder.addInterceptorFirstメソッドを使用します。 XML Beanワイヤリングを使用した以下の例。 (ファクトリー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クラスを引き続き使用しますが、現在は非推奨です。うまくいけば、これは将来のリリースで対処されるでしょう。

32
John Rix

http://docs.spring.io/spring-ws/site/apidocs/org/springframework/ws/transport/http/HttpComponentsMessageSender.html をSpring WebServiceメッセージとして使用したとき、それは私に起こります送信者。その場合、HttpPutやHttpRequestなどは簡単にアクセスできません。そのため、HttpClientBuilderを使用してHttpClientを構築し、原因となったRequestContentの前にHttpRequestInterceptorを挿入しました。

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());
13
igor.zh

ジョンリックスの答え は正しい考えを持っています。プレーンなJavaでこれを行う方法は次のとおりです。

HttpClient client = HttpClients.custom()
    .addInterceptorFirst(new RemoveSoapHeadersInterceptor())
    .build();
3
Muhd

チェックアウト http://docjar.org/docs/api/org/Apache/http/protocol/RequestContent.html 自分で設定した場合は、例外がスローされることに気づくでしょう。したがって、内部の作業はコンテンツの長さを自動的に設定します。これは、「0」に設定するには、エンティティをnullに設定する必要があることも意味します。

1
Prannay

@John Rixの回答このコードは問題の解決に役立ちました

    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();
0
Alok