2015-01-13 5 views
21

मैं ओकेएचटीपी लाइब्रेरी के माध्यम से अपने http कॉल को लागू करता हूं। सबकुछ ठीक काम करता है, लेकिन मैंने देखा कि, जब मैं प्रतिक्रिया की स्ट्रिंग के रूप में शरीर को IllegalStateException पर फेंक दूंगा। यही है, मैं करता हूं (उदाहरण के लिए): Log.d("TAG", response.body().string()) और इसके बाद मैं वास्तव में processResponse(response.body().string()) जैसे स्ट्रिंग का उपयोग करना चाहता हूं। लेकिन वह दूसरी कॉल संदेश closed के साथ अपवाद फेंकता है।ओकेएचटीपी प्रतिक्रिया की बॉडी स्ट्रिंग तक पहुंचने से दो बार परिणाम होता है IllegalStateException: बंद

यह कैसे संभव हो सकता है कि एक स्ट्रिंग तक पहुंचने से विफलता में दो बार परिणाम हो? मैं कुछ मानों (जैसे हेडर, बॉडी, स्टेटसोड) को बचाने के लिए केवल एक रैपर/डमी ऑब्जेक्ट जोड़ने की ज़रूरत के बिना उस प्रतिक्रिया को संसाधित करना चाहता हूं।

उत्तर

25

string प्रतिक्रिया पर विधि इनपुट (नेटवर्क) स्ट्रीम को पढ़ेगी और इसे एक स्ट्रिंग में परिवर्तित कर देगी। तो यह गतिशील रूप से स्ट्रिंग बनाता है और इसे आपके पास लौटाता है। दूसरी बार जब आप इसे कॉल करते हैं, तो नेटवर्क स्ट्रीम पहले से ही खाई जा चुकी है और अब उपलब्ध नहीं है।

आपको string का परिणाम स्ट्रिंग वैरिएबल में सहेजना चाहिए, और फिर इसे जितनी बार आवश्यक हो उतनी बार एक्सेस करना चाहिए।

+0

मुझे उम्मीद कर रहा था कि मैं केवल 'प्रतिक्रिया' ऑब्जेक्ट का पुन: उपयोग कर सकता हूं। OkHttp का उपयोग करने से पहले मैंने एक कस्टम ApiResult ऑब्जेक्ट लौटाया जहां मैंने अभी सभी प्रासंगिक जानकारी सहेजी थी, लेकिन यह सिर्फ एक डुप्लिकेट आईएमओ है। – degill

+0

शायद आपको github पर यह [मुद्दा] (https://github.com/square/okhttp/issues/1240) चेकआउट करना चाहिए। – penkzhou

+0

मैं आपका पॉइंट देखता हूं। मुझे लगता है कि वे इसे परिणाम को कैश किए बिना जितना संभव हो उतना कम स्तर के रूप में रखना चाहते थे जिसे कभी भी –

20

इस मुद्दे की व्याख्या के लिए Greg Ennis' answer देखें।

क्लोन यह पढ़ने से पहले बफर:

हालांकि, अगर आप आसानी से एक चर में परिणाम पारित नहीं हो सकता, लेकिन अभी भी प्रतिक्रिया शरीर का उपयोग करने की जरूरत है दो बार आप एक और विकल्प होता है। इसके द्वारा मूल बफर न तो खाली हो गया है और न ही बंद है।

ResponseBody responseBody = response.body(); 
BufferedSource source = responseBody.source(); 
source.request(Long.MAX_VALUE); // request the entire body. 
Buffer buffer = source.buffer(); 
// clone buffer before reading from it 
String responseBodyString = buffer.clone().readString(Charset.forName("UTF-8")) 
Log.d("TAG", responseBodyString); 

यह दृष्टिकोण खुद को वर्ग द्वारा परियोजना okhttp में HttpLoggingInterceptor में प्रयोग किया जाता है: इस स्निपेट देखें।

+0

बहुत बहुत धन्यवाद। वास्तव में इस तरह की जरूरत है अन्यथा मुझे 20-30 स्थानों की तरह इसे बदलने की आवश्यकता होगी :) –

1

ग्रेग एननिस के उत्तर के अलावा बीटीडब्ल्यू मैं बता सकता हूं कि जब मैं प्रतिक्रिया भूल गया था तो मैं किस समय यह भूल गया था। घड़ी()। स्ट्रिंग() घड़ी विंडो में। तो डीबगर के तहत शरीर घड़ी में पढ़ रहा था और उसके बाद नेटवर्क स्ट्रीम बंद कर दी गई थी।

0

user2011622 और Greg Ennis के उत्तरों पर थोड़ा सा विस्तार करने के लिए, मैंने एक विधि बनाई है जो आपको शरीर का एक पूर्ण क्लोन बनाने में मदद करता है, जिससे आप शरीर की प्रत्येक प्रति को अलग से उपभोग कर सकते हैं। मैं इस विधि का उपयोग रेट्रोफिट 2

/** 
* Clones a raw buffer so as not to consume the original 
* @param rawResponse the original {@link okhttp3.Response} as returned 
*     by {@link Response#raw()} 
* @return a cloned {@link ResponseBody} 
*/ 
private ResponseBody cloneResponseBody(okhttp3.Response rawResponse) { 
    final ResponseBody responseBody = rawResponse.body(); 
    final Buffer bufferClone = responseBody.source().buffer().clone(); 
    return ResponseBody.create(responseBody.contentType(), responseBody.contentLength(), bufferClone); 
} 
+0

बस प्रतिक्रिया के साथ विधि को कॉल करें, आपको प्रतिक्रिया शरीर की एक और प्रतिलिपि मिल जाएगी लेकिन मूल उपलब्ध रहेगा (खुला) –

+0

स्रोतों में देखें और उसी चीज को लागू करें जो मेरे पास पहले है (क्लोन स्रोत से नया आइसेंटेंस), मैं इससे परिचित नहीं हूं –

संबंधित मुद्दे

 संबंधित मुद्दे