Content-Length 标头已存在
Posted
技术标签:
【中文标题】Content-Length 标头已存在【英文标题】:Content-Length header already present 【发布时间】:2010-07-26 05:21:20 【问题描述】:我正在使用 android 中包含的 Apache HttpClient (4.1) 来执行 HttpPut。我已经验证我只有 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: 在 org.apache.http.protocol.RequestContent.process(RequestContent.java:70) 在 org.apache.http.protocol.BasicHttpProcessor.process(BasicHttpProcessor.java:290)
有什么想法吗?
【问题讨论】:
【参考方案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 标头。
使用 HttpClientBuilder.addInterceptorFirst 方法将此拦截器注入到您自己的 HttpClient 实例中。下面的示例使用 XML bean 连接。如果有人知道构造 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>
或者,如果可以的话,只允许 HttpComponentsMessageSender 构造它自己的 HttpClient 实例,而不是传递一个给它。对此的小提示:从 spring-ws 2.2.0-RELEASE 开始,HttpComponentsMessageSender 的默认构造函数继续使用现在已弃用的 DefaultHttpClient 类。希望这将在未来的版本中得到解决。
【讨论】:
【参考方案2】:我自己没有使用过 HttpClient,但我怀疑问题在于 putMethod.setEntity(...)
隐式提供了内容长度,而您还通过 putMethod.addHeader(...)
调用之一显式设置它。
【讨论】:
没错。除非您使用普通的 Socket,否则您不必自己在 Java 中设置 Content-Length。 @EJP - 或 java.net URLConnection 类。 不,他们是为你做的。如果你不使用这些,你只需要设置它。 很公平,但 Javadoc 并没有说它不能构建自己的 Content-Length 标头,它还说'在常见情况下,所有预连接参数和一般请求属性可以忽略:预连接参数和请求属性默认为合理值。对于这个接口的大多数客户端来说,只有两个有趣的方法……' 顺便说一句 - 我能够通过设置请求拦截器(最后)并查看修改后的请求来验证这一点。它显示已经设置的 Content-Length。【参考方案3】:当我使用 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());
【讨论】:
【参考方案4】:John Rix's answer 有正确的想法。以下是使用普通 java 的方法:
HttpClient client = HttpClients.custom()
.addInterceptorFirst(new RemoveSoapHeadersInterceptor())
.build();
【讨论】:
你必须导入那个拦截器类import org.springframework.ws.transport.http.HttpComponentsMessageSender.RemoveSoapHeadersInterceptor;
【参考方案5】:
如果您结帐http://docjar.org/docs/api/org/apache/http/protocol/RequestContent.html,您会注意到如果您自己设置了它,它会引发该异常。因此,内部工作自动设置内容长度。这也意味着,要将其设置为“0”,您需要将实体设置为 null。
【讨论】:
【参考方案6】:@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();
【讨论】:
以上是关于Content-Length 标头已存在的主要内容,如果未能解决你的问题,请参考以下文章
ERROR 验证错误:Lambda 函数结果验证失败,该函数尝试删除只读标头,标头名称:Content-Length
如何从使用 axios 发送的 POST 请求中获取 Content-Length 标头?