2010-07-26 6 views
24

Estoy utilizando el Apache HttpClient (4.1) incluido en Android para ejecutar un HttpPut. He verificado que solo tengo 1 encabezado de longitud de contenido. Sin embargo, cada vez que envío la solicitud, recibo una excepción de protocolo sobre el encabezado Content-Length ya especificado.encabezado Content-Length ya presente

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 

causada por: org.apache.http.ProtocolException: cabecera Content-Length ya presente en org.apache.http.protocol.RequestContent.process (RequestContent.java:70) en org.apache. http.protocol.BasicHttpProcessor.process (BasicHttpProcessor.java:290)

¿Alguna idea?

Respuesta

26

No he usado HttpClient, pero sospecho que el problema es que putMethod.setEntity(...) está proporcionando implícitamente una longitud de contenido y también lo está configurando explícitamente a través de una de las llamadas putMethod.addHeader(...).

+1

Exactamente. Nunca tendrá que configurar Content-Length usted mismo en Java a menos que esté utilizando un socket simple. – EJP

+0

@EJP - o las clases java.net URLConnection. –

+0

No, lo hacen por ti. Solo tiene que configurarlo si * no * usa esos. – EJP

13

Eso me sucede cuando usé http://docs.spring.io/spring-ws/site/apidocs/org/springframework/ws/transport/http/HttpComponentsMessageSender.html como un Spring WebService Message Sender. En ese caso, la materia como HttpPut o HttpRequest no son de fácil acceso, por lo que, la construcción de HttpClient con HttpClientBuilder, que terminó la inserción de un HttpRequestInterceptor frente al RequestContent culpable:

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()); 
24

Como ha señalado igor.zh, este puede ocurrir un problema si se usa la clase HttpComponentsMessageSender de Spring. Sin embargo, para ser más preciso, esto es solo un problema si pasa su propia instancia de HttpClient al constructor HttpComponentsMessageSender; de lo contrario, el problema se maneja automáticamente.

partir de la primavera-WS 2.1.4, la subclase HttpComponentsMessageSender.RemoveSoapHeadersInterceptor que se utiliza en el constructor por defecto se hizo pública para abordar esta cuestión (ver https://jira.spring.io/browse/SWS-835) y por lo tanto se puede utilizar en sus propios HttpClient instancias, en vez de escribir su propia clase para hacerlo. También borra el encabezado HTTP.TRANSFER_ENCODING.

Utilice el método HttpClientBuilder.addInterceptorFirst para inyectar este interceptor en su propia instancia de HttpClient. Ejemplo a continuación utilizando el cableado de beans XML. Si alguien conoce una forma más concisa de construir la instancia de HttpClient (aparte de escribir una clase de beans de fábrica), ¡soy todo oídos!

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

Alternativamente, si se puede, simplemente permiten HttpComponentsMessageSender para construir su propia HttpClient ejemplo, en lugar de pasar uno a ella. Nota menor sobre esto: a partir de spring-ws 2.2.0-RELEASE, el constructor predeterminado para HttpComponentsMessageSender continúa usando la clase DefaultHttpClient, que ahora está en desuso. Espero que esto se aborde en una versión futura.

1

John Rix's answer tiene la idea correcta. Así es como lo hace con Java simple:

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