2010-07-26 18 views
24

मैं एक HttpPut निष्पादित करने के लिए एंड्रॉइड में शामिल Apache HttpClient (4.1) का उपयोग कर रहा हूं। मैंने सत्यापित किया है कि मेरे पास केवल 1 सामग्री-लंबाई वाला हेडर है। हालांकि, हर बार जब मैं अनुरोध भेजता हूं, तो मुझे पहले से निर्दिष्ट सामग्री-लंबाई शीर्षलेख के बारे में प्रोटोकॉल अपवाद मिलता है। org.apache.http.ProtocolException:सामग्री-लंबाई शीर्षलेख पहले से मौजूद है

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.protocol.RequestContent.process (RequestContent.java:70) पर org.apache पर। http.protocol.BasicHttpProcessor.process (BasicHttpProcessor.java990)

कोई विचार?

उत्तर

26

मैंने खुद एचटीपी क्लाइंट का उपयोग नहीं किया है, लेकिन मुझे संदेह है कि समस्या यह है कि putMethod.setEntity(...) स्पष्ट रूप से सामग्री की लंबाई की आपूर्ति कर रहा है और आप इसे putMethod.addHeader(...) कॉलों में से एक के माध्यम से स्पष्ट रूप से सेट कर रहे हैं।

+1

बिल्कुल। जब तक आप एक सादे सॉकेट का उपयोग नहीं कर लेते हैं, तब तक आपको जावा में सामग्री-लंबाई को स्वयं सेट नहीं करना पड़ेगा। – EJP

+0

@EJP - या java.net URL कनेक्शन वर्ग। –

+0

नहीं, वे आपके लिए यह करते हैं। आपको केवल इसे सेट करना होगा यदि आप * उन का उपयोग नहीं कर रहे हैं। – EJP

1

यदि आप http://docjar.org/docs/api/org/apache/http/protocol/RequestContent.html चेकआउट करते हैं तो आप देखेंगे कि अगर आप इसे स्वयं सेट कर चुके हैं तो यह अपवाद फेंकता है। इसलिए, आंतरिक कार्य सामग्री की लंबाई स्वचालित रूप से सेट करता है। इसका अर्थ यह भी है कि इसे "0" पर सेट करने के लिए, आपको इकाई को शून्य पर सेट करने की आवश्यकता है।

13

यह तब होता है जब मैंने स्प्रिंग वेब सेवा संदेश प्रेषक के रूप में http://docs.spring.io/spring-ws/site/apidocs/org/springframework/ws/transport/http/HttpComponentsMessageSender.html का उपयोग किया था। उस मामले में की तरह 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()); 
24

रूप igor.zh द्वारा कहे अनुसार, इस स्प्रिंग के HttpComponentsMessageSender क्लास का उपयोग करते समय समस्या हो सकती है। हालांकि, अधिक सटीक होने के लिए, यह केवल एक समस्या है यदि आप HttpComponentsMessageSender निर्माता में HttpClient का अपना उदाहरण गुजर रहे हैं - समस्या स्वचालित रूप से अन्यथा संभाली जाती है।

वसंत-ws 2.1.4 के रूप में, HttpComponentsMessageSender.RemoveSoapHeadersInterceptor उपवर्ग कि डिफ़ॉल्ट निर्माता में प्रयोग किया जाता है इस मुद्दे (https://jira.spring.io/browse/SWS-835 देखें) को संबोधित करने को सार्वजनिक कर दिया गया था और इसलिए लिखने की बजाय अपने खुद के HttpClient मामलों में इस्तेमाल किया जा सकता अपने ऐसा करने के लिए अपनी कक्षा। यह HTTP.TRANSFER_ENCODING हेडर को भी साफ़ करता है।

HttpClientBuilder.addInterceptor का उपयोग करें इस इंटरसेप्टर को अपने स्वयं के 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 उदाहरण के निर्माण के लिए अनुमति देते हैं। इस पर मामूली नोट: वसंत-ws 2.2.0-रिलीज के रूप में, HttpComponentsMessageSender के लिए डिफ़ॉल्ट कन्स्ट्रक्टर DefaultHttpClient क्लास का उपयोग करना जारी रखता है, जिसे अब बहिष्कृत किया गया है। उम्मीद है कि भविष्य में रिलीज में इसे संबोधित किया जाएगा।

1

John Rix's answer का सही विचार है। यहां बताया गया है कि आप इसे सादा जावा के साथ कैसे करते हैं:

HttpClient client = HttpClients.custom() 
    .addInterceptorFirst(new RemoveSoapHeadersInterceptor()) 
    .build(); 
संबंधित मुद्दे