简体   繁体   English

Content-Length 标头已存在

[英]Content-Length header already present

I am using the Apache HttpClient (4.1) included in Android to execute a HttpPut.我正在使用 Android 中包含的 Apache HttpClient (4.1) 来执行 HttpPut。 I have verified that I only have 1 content-length header.我已经验证我只有 1 个内容长度标头。 However, every time I send the request, I get a protocol exception about the Content-Length header already specified.但是,每次发送请求时,我都会收到有关已指定 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

Caused by: org.apache.http.ProtocolException: Content-Length header already present at org.apache.http.protocol.RequestContent.process(RequestContent.java:70) at org.apache.http.protocol.BasicHttpProcessor.process(BasicHttpProcessor.java:290)原因:org.apache.http.ProtocolException: Content-Length 标头已经存在于 org.apache.http.protocol.RequestContent.process(RequestContent.java:70) 的 org.apache.http.protocol.BasicHttpProcessor.process(BasicHttpProcessor .java:290)

Any ideas?有任何想法吗?

As pointed out by igor.zh, this problem can occur if using Spring's HttpComponentsMessageSender class.正如igor.zh 所指出的,如果使用Spring 的HttpComponentsMessageSender 类,就会出现这个问题。 To be more precise though, this is only a problem if you are passing your own instance of HttpClient into the HttpComponentsMessageSender constructor - the issue is handled automatically otherwise.更准确地说,如果您将自己的 HttpClient 实例传递给 HttpComponentsMessageSender 构造函数,这只是一个问题 - 否则问题会自动处理。

As of spring-ws 2.1.4, the HttpComponentsMessageSender.RemoveSoapHeadersInterceptor subclass that is used in the default constructor was made public to address this issue (see https://jira.spring.io/browse/SWS-835 ) and so can be used in your own HttpClient instances instead of writing your own class to do it.从 spring-ws 2.1.4 开始,默认构造函数中使用的 HttpComponentsMessageSender.RemoveSoapHeadersInterceptor 子类已公开以解决此问题(请参阅https://jira.spring.io/browse/SWS-835 ),因此可以在您自己的 HttpClient 实例中使用,而不是编写您自己的类来执行此操作。 It also clears the HTTP.TRANSFER_ENCODING header.它还清除 HTTP.TRANSFER_ENCODING 标头。

Use the HttpClientBuilder.addInterceptorFirst method to inject this interceptor into your own HttpClient instance.使用 HttpClientBuilder.addInterceptorFirst 方法将此拦截器注入您自己的 HttpClient 实例。 Example below using XML bean wiring.下面的示例使用 XML bean 连接。 If anybody knows a more concise way of constructing the HttpClient instance (aside from writing a factory bean class), I'm all ears!如果有人知道构造 HttpClient 实例的更简洁的方法(除了编写工厂 bean 类),我全神贯注!

<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>

Alternatively, if you can, just allow HttpComponentsMessageSender to construct its own HttpClient instance rather than passing one to it.或者,如果可以的话,只允许 HttpComponentsMessageSender 构造它自己的 HttpClient 实例,而不是传递一个给它。 Minor note on this: as of spring-ws 2.2.0-RELEASE, the default constructor for HttpComponentsMessageSender continues to use the DefaultHttpClient class, which is now deprecated.对此的小提示:从 spring-ws 2.2.0-RELEASE 开始,HttpComponentsMessageSender 的默认构造函数继续使用现在已弃用的 DefaultHttpClient 类。 Hopefully this will be addressed in a future release.希望这将在未来的版本中得到解决。

我自己没有使用过 HttpClient ,但我怀疑问题在于putMethod.setEntity(...)隐式提供了内容长度,并且您还通过其中一个putMethod.addHeader(...)调用显式设置它.

That happens to me when I used http://docs.spring.io/spring-ws/site/apidocs/org/springframework/ws/transport/http/HttpComponentsMessageSender.html as a Spring WebService Message Sender.当我使用http://docs.spring.io/spring-ws/site/apidocs/org/springframework/ws/transport/http/HttpComponentsMessageSender.html作为 Spring WebService 消息发送器时,这种情况发生在我身上。 In that case the stuff like HttpPut or HttpRequest are not easily accessible, so, building HttpClient with HttpClientBuilder, I ended up inserting a HttpRequestInterceptor in front of the culprit RequestContent :在那种情况下,像 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());

John Rix's answer has the right idea.约翰·里克斯的回答有正确的想法。 Here's how you do it with plain java:以下是使用普通 java 的方法:

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

If you checkout http://docjar.org/docs/api/org/apache/http/protocol/RequestContent.html you'll notice that it throws that exception if you've set it yourself.如果您检查http://docjar.org/docs/api/org/apache/http/protocol/RequestContent.html ,您会注意到如果您自己设置它会引发该异常。 Therefore, the internal working set the content length automatically.因此,内部工作自动设置内容长度。 This also means, to set it to "0", you need to set the entity to null.这也意味着,要将其设置为“0”,您需要将实体设置为空。

If you are adopting the XML configuration answer by John Rix, make sure to add a depends-on attribute to the httpClient bean so the RemoveSoapHeadersInterceptor interceptor is added to the ClientBuilder before the httpClient bean gets created.如果您采用 John Rix 的 XML 配置答案,请确保向httpClient bean 添加一个depends-on属性,以便在创建httpClient bean之前RemoveSoapHeadersInterceptor拦截器添加到ClientBuilder SOAP headers removal hasn't taken effect until I have done so.在我这样做之前,SOAP 标头删除尚未生效。

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

@John Rix's answer This code helped solved the problem @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();

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM