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)
何か案は?
私は自分でHttpClientを使用していませんが、問題はputMethod.setEntity(...)
が暗黙的にコンテンツの長さを提供しており、putMethod.addHeader(...)
呼び出しの1つを介して明示的に設定していることだと思います。
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クラスを引き続き使用しますが、現在は非推奨です。うまくいけば、これは将来のリリースで対処されるでしょう。
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());
ジョンリックスの答え は正しい考えを持っています。プレーンなJavaでこれを行う方法は次のとおりです。
HttpClient client = HttpClients.custom()
.addInterceptorFirst(new RemoveSoapHeadersInterceptor())
.build();
チェックアウト http://docjar.org/docs/api/org/Apache/http/protocol/RequestContent.html 自分で設定した場合は、例外がスローされることに気づくでしょう。したがって、内部の作業はコンテンツの長さを自動的に設定します。これは、「0」に設定するには、エンティティをnullに設定する必要があることも意味します。
@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();