2012-02-14 79 views
12

我正在努力使用Twitter的Finagle庫來實現對SOAP服務器的HTTP請求。使用Finagle進行簡單的Scala SOAP客戶端

下面的代碼執行成功(使用 java.net.URL中)在第一測試中,但我在使用第二測試很難(使用 欺騙客戶端)。我究竟做錯了什麼?

此外,我一直被拖入和寫作風格。如果 你可以幫我讓Finagle位更像'scala'一樣,我會很感激 。

這裏所說:

import java.net.InetSocketAddress 
import scala.xml.{Elem, XML} 
import org.jboss.netty.buffer.ChannelBuffers 
import org.jboss.netty.util.CharsetUtil.UTF_8 
import com.twitter.finagle.Service; 
import com.twitter.finagle.builder.ClientBuilder; 
import com.twitter.finagle.http.Http; 
import org.jboss.netty.handler.codec.http._ 

class SoapClient { 
    private def error(msg: String) = { 
    println("SoapClient error: " + msg) 
    } 

    def wrap(xml: Elem): String = { 
    val buf = new StringBuilder 
    buf.append("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone= 
\"no\"?>\n") 
    buf.append("<SOAP-ENV:Envelope xmlns:SOAP-ENV=\"http:// 
schemas.xmlsoap.org/soap/envelope/\">\n") 
    buf.append("<SOAP-ENV:Body>\n") 
    buf.append(xml.toString) 
    buf.append("\n</SOAP-ENV:Body>\n") 
    buf.append("</SOAP-ENV:Envelope>\n") 
    buf.toString 
    } 

    def sendWithJavaNetURL(host: String, req: Elem): Option[Elem] = { 
    val url = new java.net.URL(host) 
    val outs = wrap(req).getBytes 
    val conn = 
url.openConnection.asInstanceOf[java.net.HttpURLConnection] 
    try { 
     conn.setRequestMethod("POST") 
     conn.setDoOutput(true) 
     conn.setRequestProperty("Content-Length", outs.length.toString) 
     conn.setRequestProperty("Content-Type", "text/xml") 
     conn.getOutputStream.write(outs) 
     conn.getOutputStream.close 
     Some(XML.load(conn.getInputStream)) 
    } 
    catch { 
     case e: Exception => error("post: " + e) 
     error("post:" + 
scala.io.Source.fromInputStream(conn.getErrorStream).mkString) 
     None 
    } 
    } 

    def sendWithFinagle(host: String, path: String, req: Elem) = { 
    val clientService: Service[HttpRequest, HttpResponse] = 
ClientBuilder() 
     .codec(Http()) 
     .hosts(new InetSocketAddress(host, 80)) 
     .hostConnectionLimit(1) 
     .build() 
    val request: HttpRequest = new 
DefaultHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.POST, "/") 
    val soapPacket: String = wrap(req) 
    request.setContent(ChannelBuffers.copiedBuffer(soapPacket, UTF_8)) 
    request.setHeader("Content-Lenght", soapPacket.length()) 
    request.setHeader("Content-Type", "text/xml") 
    request.setUri("path") 
    val client = clientService(request) 
    val response = client.get() 
    println(response) 
    } 
} 

object SoapTest { 

    def testWithJavaNetURL { 
    val host = "https://apitest.authorize.net/soap/v1/Service.asmx" 
    val req = <IsAlive xmlns="https://api.authorize.net/soap/v1/"/> 
    val cli = new SoapClient 
    println("##### Test with Java Net URL: request:\n" + 
cli.wrap(req)) 
    val resp = cli.sendWithJavaNetURL(host, req) 
    if (resp.isDefined) { 
     println("##### response:\n" + resp.get.toString) 
    } 
    } 

    def testWithFinagle { 
    val host = "apitest.authorize.net" 
    val path = "/soap/v1/Service.asmx" 
    val req = <IsAlive xmlns="https://api.authorize.net/soap/v1/"/> 
    val cli = new SoapClient 
    println("##### Test with Finagle: request:\n" + cli.wrap(req)) 
    cli.sendWithFinagle(host, path, req) 
    } 

    def main(args: Array[String]) { 
    testWithJavaNetURL 
    testWithFinagle 
    } 

回答

13

讓 - 菲利普,從Finagles forum,請提供一個answer on github

以下是完整的工作,並很好地更新代碼:

import java.net.InetSocketAddress 
import scala.xml.{Elem, XML} 
import org.jboss.netty.buffer.ChannelBuffers 
import org.jboss.netty.util.CharsetUtil.UTF_8 
import com.twitter.finagle.Service; 
import com.twitter.finagle.builder.ClientBuilder; 
import com.twitter.finagle.http.{Http, RequestBuilder}; 
import org.jboss.netty.handler.codec.http._ 
import org.jboss.netty.buffer.ChannelBuffers.wrappedBuffer 
import java.net.URL 
class SoapClient { 
    private def error(msg: String) = { 
    println("SoapClient error: " + msg) 
    } 
    def wrap(xml: Elem): String = { 
    val wrapper = <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"> 
       <SOAP-ENV:Body> 
        {xml} 
       </SOAP-ENV:Body> 
       </SOAP-ENV:Envelope> 
    wrapper.toString 
    } 
    def sendWithJavaNetURL(host: String, req: Elem): Option[Elem] = { 
    val url = new java.net.URL(host) 
    val outs = wrap(req).getBytes 
    val conn = 
url.openConnection.asInstanceOf[java.net.HttpURLConnection] 
    try { 
     conn.setRequestMethod("POST") 
     conn.setDoOutput(true) 
     conn.setRequestProperty("Content-Length", outs.length.toString) 
     conn.setRequestProperty("Content-Type", "text/xml") 
     conn.getOutputStream.write(outs) 
     conn.getOutputStream.close 
     Some(XML.load(conn.getInputStream)) 
    } 
    catch { 
     case e: Exception => error("post: " + e) 
     error("post:" + 
scala.io.Source.fromInputStream(conn.getErrorStream).mkString) 
     None 
    } 
    } 
    def sendWithFinagle(host: String, path: String, req: Elem) = { 
    val clientService: Service[HttpRequest, HttpResponse] = 
ClientBuilder() 
     .codec(Http()) 
     .hosts(new InetSocketAddress(host, 443)) 
     .tls(host) 
     .hostConnectionLimit(1) 
     .build() 
    val payload = wrap(req).getBytes("UTF-8") 
    val request: HttpRequest = RequestBuilder().url(new URL("https", host, 443, path)) 
               .setHeader("Content-Type", "text/xml") 
               .setHeader("Content-Length", payload.length.toString) 
               .buildPost(wrappedBuffer(payload)) 

    val client = clientService(request) 

    for(response <- client) { 
     println(response) 
     println(response.getContent.toString("UTF-8")) 
    } 
    // val response = client.get() 
    } 
} 

object SoapTest { 
    def testWithJavaNetURL { 
    val host = "https://apitest.authorize.net/soap/v1/Service.asmx" 
    val req = <IsAlive xmlns="https://api.authorize.net/soap/v1/"/> 
    val cli = new SoapClient 
    println("##### Test with Java Net URL: request:\n" + 
cli.wrap(req)) 
    val resp = cli.sendWithJavaNetURL(host, req) 
    if (resp.isDefined) { 
     println("##### response:\n" + resp.get.toString) 
    } 
    } 
    def testWithFinagle { 
    val host = "apitest.authorize.net" 
    val path = "/soap/v1/Service.asmx" 
    val req = <IsAlive xmlns="https://api.authorize.net/soap/v1/"/> 
    val cli = new SoapClient 
    println("##### Test with Finagle: request:\n" + cli.wrap(req)) 
    cli.sendWithFinagle(host, path, req) 
    } 
    def main(args: Array[String]) { 
    testWithJavaNetURL 
    testWithFinagle 
    } 
} 

SoapTest.main(Array[String]())