2012-10-20 17 views
6

मुझे एक webservice कॉल करना है जो मुझे एक बाइनरी फ़ाइल की सामग्री देता है। मैं तो बस वापस मेरे नियंत्रक के फोन करने वाले को एक ही सामग्री देना चाहता हूँ:प्ले: बाइनरी webservice प्रतिक्रिया

val blobPromise = WS.url("http://url/to/webservice/file.txt").get() 
Async { 
    blobPromise.map(f => Ok(f.body)) 
} 

यह पाठ फ़ाइलों के लिए काम करता है, लेकिन द्विआधारी फ़ाइलें दूषित हो जाएगी। मैं यहाँ क्या गलत कर रहा हूँ? (शायद यह f.body कि एक स्ट्रिंग के लिए वेब सेवा से द्विआधारी परिणाम encodes है लेकिन मैं कच्चे डेटा कैसे मिल सकता है??)

मुझे पता है, यह बड़ी फ़ाइलों के लिए एक अच्छा तरीका नहीं है - मैं प्ले डॉक्स में पढ़ा है लगभग Streaming HTTP responses, लेकिन यह मेरे लिए प्ले फ्रेमवर्क के साथ शुरुआत के रूप में जटिल लगता है।

उत्तर

8

आप f.ahcResponse.gerResponseBodyAsBytes का उपयोग कर कच्चा डेटा प्राप्त कर सकते हैं। लेकिन मुझे लगता है, यह पूरी प्रतिक्रिया स्मृति में लोड करेगा, जो अक्षम है।

आप स्ट्रीमिंग कार्यक्षमता का उपयोग कर सकते हैं! इस तरह काफी आसानी से प्रदान करता है:

Async { 
    WS.url("http://url/to/webservice/file.txt").get().map(response => { 
    val asStream: InputStream = response.ahcResponse.getResponseBodyAsStream 
    Ok.stream(Enumerator.fromStream(asStream)) 
    }) 
} 
+0

बाइनरी डेटा के साथ अब 'f.ahcResponse.getResponseBodyAsBytes' के साथ दोनों समाधानों का बहुत धन्यवाद। स्ट्रीमिंग कार्यक्षमता मैंने सोचा है की तुलना में आसान लगता है ... :-) – Sonson123

+3

क्या यह ब्लॉक नहीं करता है? इनपुटस्ट्रीम आमतौर पर करते हैं .... –

+0

असल में यह तब से अवरुद्ध नहीं होता जब आप इसे पढ़ते हैं ... लेकिन केवल इसलिए कि यह सब स्मृति में पहले पढ़ा जाता है। इससे बचने के लिए, आपको 'get()' के ओवरलोडेड फॉर्म का उपयोग करना होगा जो उपभोक्ता फ़ंक्शन तर्क लेता है: '[ए] प्राप्त करें (उपभोक्ता: (प्रतिक्रिया हेडर) ⇒ Iteratee [ऐरे [बाइट], ए]) ' –

3

आप सामग्री स्ट्रीम करना चाहते हैं:

def streamFromWS = Action.async { request => 
    import play.api.libs.iteratee.Concurrent.joined 

    val resultPromise = Promise[SimpleResult] 

    val consumer = { rs: ResponseHeaders => 
    val (wsConsumer, stream) = joined[Array[Byte]] 
    val contentLength = rs.headers.get("Content-Length").map(_.head).get 
    val contentType = rs.headers.get("Content-Type").map(_.head).getOrElse("binary/octet-stream") 
    resultPromise.success(
     SimpleResult(
     header = ResponseHeader(
      status = OK, 
      headers = Map(
      CONTENT_LENGTH -> contentLength, 
      CONTENT_DISPOSITION -> s"""attachment; filename="file.txt"""", 
      CONTENT_TYPE -> contentType 
     )), 
     body = stream 
    )) 
    wsConsumer 
    } 

    WS.url("http://url/to/webservice/file.txt").get(consumer).map(_.run) 

    resultPromise.future 
} 
+0

बहुत बहुत धन्यवाद, ऐसा लगता है कि नौकरी करने के लिए "शामिल" परमिट –

1

यान साइमन जवाब के आधार पर, यहाँ एक सरल CORS प्रॉक्सी कार्यान्वयन डाउनलोड किया दूरस्थ फ़ाइलें स्ट्रीम और उन्हें स्ट्रीम करने के लिए अनुमति देता है है ग्राहक के लिए। यह स्मृति में सभी फाइल लोड नहीं करता है।

import play.api.libs.iteratee._ 

    private def getAndForwardStream(requestHolder: WSRequestHolder)(computeHeaders: ResponseHeaders => ResponseHeader): Future[SimpleResult] = { 
    val resultPromise = scala.concurrent.Promise[SimpleResult] 
    requestHolder.get { wsResponseHeaders: ResponseHeaders => 
     val (wsResponseIteratee, wsResponseEnumerator) = Concurrent.joined[Array[Byte]] 
     val result = SimpleResult(
     header = computeHeaders(wsResponseHeaders), 
     body = wsResponseEnumerator 
    ) 
     resultPromise.success(result) 
     wsResponseIteratee 
    } 
    resultPromise.future 
    } 

    def corsProxy(url: URL) = Action.async { implicit request => 
    val requestHolder = WS.url(url.toString).withRequestTimeout(10000) 
    getAndForwardStream(requestHolder) { wsResponseHeaders: ResponseHeaders => 
     // We use the WS response headers and transmit them unchanged to the client, except we add the CORS header... 
     val originToAllow = request.headers.get("Origin").getOrElse("*") 
     val headers = wsResponseHeaders.headers.mapValues(_.head) + ("Access-Control-Allow-Origin" -> originToAllow) 
     ResponseHeader(
     status = wsResponseHeaders.status, 
     headers = headers 
    ) 
    } 
    } 

यहां महत्वपूर्ण हिस्सा play.api.libs.iteratee.Concurrent.joined[Array[Byte]] का उपयोग है। यह एक Iteratee/Enumerator जोड़ी बनाने की अनुमति देता है ताकि जब भी आप Iteratee में बाइट जोड़ते हैं, तो इन बाइट्स गणक द्वारा गणनाकर्ता होंगे।

  • आप एक Iteratee WS प्रतिक्रिया का उपभोग करने की जरूरत है:

    यह टुकड़ा याद आ रही है क्योंकि था।

  • प्ले फ्रेमवर्क प्रतिक्रिया उत्पन्न करने के लिए आपको एक गणनाकर्ता की आवश्यकता है।
+0

नई एपीआई धारा() को प्ले 2.3: के साथ आ रहा है http://www.playframework.com/documentation/2.3.x/api/scala/ index.html # play.api.libs.ws.WSRequestHolder इसके साथ, आपको शामिल होने की आवश्यकता नहीं है [] अब –

+0

धन्यवाद @YannSimon thx;) –

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