HTTP-Anfrage in Scala ausführen

74

Ich versuche, eine einfache POST-Anfrage an einen Webservice zu senden, der XML in Scala zurückgibt.

Es scheint, dass Dispatch die Standardbibliothek ist, die für diese Aufgabe verwendet wird, aber ich kann keine Dokumentation dafür finden. Die Hauptseite, die ich oben verlinke, erklärt ausführlich, was ein Versprechen ist und wie asynchrone Programmierung durchgeführt wird, dokumentiert jedoch nicht die API. Es gibt ein Periodensystem - das ein bisschen beängstigend aussieht -, aber es scheint nur für Leute nützlich zu sein, die bereits wissen, was zu tun ist und nur eine Erinnerung an die kryptische Syntax benötigen.

Es scheint auch, dass Scalaz eine Möglichkeit für HTTP hat , aber ich kann auch keine Dokumentation dafür finden.

Andrea
quelle
1
Vielen Dank für die API. Daraus kann ich möglicherweise herausfinden, wie die Bibliothek tatsächlich verwendet wird. Trotzdem hätte ich gerne etwas Zwischenprodukt, wie eine allgemeine Beschreibung der API. Ich stelle mir etwas in der Art von "Um eine POST-Anfrage zu stellen, verwenden Sie diesen Konstruktor mit diesen Parametern und so weiter" vor.
Andrea
Einverstanden, dass der Versand eine bessere Dokumentation verwenden könnte. Ich denke, Ihre beste Wette für den Moment
pr1001

Antworten:

132

Ich verwende Folgendes: https://github.com/scalaj/scalaj-http .

Hier ist eine einfache GET-Anfrage:

import scalaj.http.{Http, HttpOptions}

Http("http://example.com/search").param("q", "monkeys").asString

und ein Beispiel für einen POST:

val result = Http("http://example.com/url").postData("""{"id":"12","json":"data"}""")
  .header("Content-Type", "application/json")
  .header("Charset", "UTF-8")
  .option(HttpOptions.readTimeout(10000)).asString

Scalaj HTTP ist über SBT verfügbar:

libraryDependencies += "org.scalaj" % "scalaj-http_2.11" % "2.3.0"
Kulikov
quelle
Ich stelle mich als die einfachste Option heraus! Ich bin immer noch neugierig auf Dispatch und den Grund seiner eigentümlichen Syntax
Andrea
9
Hinweis: Das Standard-Verbindungszeitlimit ist ziemlich niedrig (100 Millis). Wenn Sie also eine empfangen java.net.SocketTimeoutException: connect timed out, fügen Sie eine Zeile wie.option(HttpOptions.connTimeout(10000))
theon
1
Es ist nicht mehr mit Scala 2.11 kompatibel, da ScalaObject entfernt wurde. Ich warte gespannt darauf, dass scalaj-http seine Bibliothek aktualisiert.
Nativ
2
@ Dalvik Ich denke, sie haben ihr Spiel aufgeräumt; einfach "org.scalaj" %% "scalaj-http" % "1.1.4"zu build.sbt hinzufügen .
Felipe
Ich bin mir nicht sicher, ob jemand andere Probleme hatte, eine Antwort mit "asParamsMap" auf dem Postweg zu erhalten, aber ich musste schließlich "asString" verwenden und dann explizit mit net.minidev.json.parser.JSONParser analysieren.
th3morg
7

Sie könnten Spray-Client verwenden . Die Dokumentation fehlt (ich musste ein wenig graben, um herauszufinden, wie GET-Anfragen mit Abfrageparametern gestellt werden ), aber es ist eine großartige Option, wenn Sie bereits Spray verwenden. Und die Dokumentation ist besser als der Versand.

Wir verwenden es bei AI2 über den Versand, weil die Bediener weniger symbolisch sind und wir bereits Spray / Schauspieler verwenden.

import spray.client.pipelining._

val url = "http://youruri.com/yo"
val pipeline: HttpRequest => Future[HttpResponse] = sendReceive

// Post with header and parameters
val responseFuture1: Future[String] = pipeline(Post(Uri(url) withParams ("param" -> paramValue), yourPostData) map (_.entity.asString)

// Post with header
val responseFuture2: Future[String] = pipeline(Post(url, yourPostData)) map (_.entity.asString)
schmmd
quelle
Der Hauptsprayentwickler ist zu akka gewechselt, sodass selbst das produktionsbereite Spray veraltet ist und AKKA-HTTP und AKKA-STREAMS die nächste Runde für http-Clients und -Server sein werden. akka.io/docs
Henry H.
5

Ich verwende den Versand: http://dispatch.databinder.net/Dispatch.html

Sie haben gerade eine neue Version (0.9.0) mit einer komplett neuen API veröffentlicht, die ich wirklich mag. Und es ist asynchron.

Beispiel von der Projektseite:

import dispatch._
val svc = url("http://api.hostip.info/country.php")
val country = Http(svc OK as.String)

for (c <- country)
  println(c)

Bearbeiten: Dies kann Ihnen helfen, https://github.com/dispatch/reboot/blob/master/core/src/main/scala/requests.scala

Drexin
quelle
Ja, ich habe die Projektseite verlinkt. Aber ich kann dort nicht finden, wie man eine einfache POST-Anfrage macht - oder sogar eine GET-Anfrage mit Parametern und / oder benutzerdefinierten Headern.
Andrea
@Andrea - versuchen Sie diesen Link: flotsam.nl/dispatch-periodic-table.html . Es scheint, dass der dispatchAutor im Moment einige Probleme mit dem Hauptdokument hat - erst gestern waren die Dokumente viel besser.
Rogach
@ Rogach ist das nicht nur für den alten Versand? Andrea: aktualisiert meinen Beitrag mit einem Link zu den Quellen
Drexin
es kann jetzt:val svc = url("http://diasporafoundation.org/").POST.setBody("test")
VasiliNovikov
3

Verwenden meiner Requests-Scala- Bibliothek:

// Mill
ivy"com.lihaoyi::requests:0.1.8"
// SBT
"com.lihaoyi" %% "requests" % "0.1.8"

Das ist so einfach wie

val r = requests.get("https://api.github.com/users/lihaoyi")

r.statusCode
// 200

r.headers("content-type")
// Buffer("application/json; charset=utf-8")

r.text
// {"login":"lihaoyi","id":934140,"node_id":"MDQ6VXNlcjkzNDE0MA==",...
val r = requests.post("http://httpbin.org/post", data = Map("key" -> "value"))

val r = requests.put("http://httpbin.org/put", data = Map("key" -> "value"))

val r = requests.delete("http://httpbin.org/delete")

val r = requests.head("http://httpbin.org/head")

val r = requests.options("http://httpbin.org/get")
Li Haoyi
quelle
Awesome Li, ich habe auch einige Zweifel, was ist, wenn ich Json Daten in request.post geben möchte, muss ich die einzelnen Schlüsselwertpaare extrahieren. Gibt es keinen einfachen Ansatz?
Mohammad Rijwan
Ich habe es verstanden, val json = "" "{" key ":" value "}" ". StripMargin val r = request.post (url, data = json) val json = ujson.read (r.text ()) println (json)
Mohammad Rijwan
2

Wenn ich einen schamlosen Plug erstellen kann, habe ich eine API namens Bee-Client, die in Scala für Javas HttpUrlConnection einfach ein Wrapper ist.

Rick-777
quelle
Vielen Dank. Gibt es Unterlagen?
Andrea
Ja, aber es ist immer noch ziemlich begrenzt. Ich arbeite an einigen Verwendungsbeispielen. Schauen Sie sich vorerst
Rick-777
Es gibt jetzt einige Dokumentationen im Wiki bitbucket.org/rickb777/lighthttpclient/wiki/Home
Rick-777
Gut! Aber es scheint privat zu sein. Ich habe momentan keine Bitbucket-Anmeldeinformationen. Wahrscheinlich hast du vergessen, das Wiki als öffentlich zu markieren
Andrea
Das tut mir leid. Ich habe die Dokumente stattdessen auf meinen Webserver verschoben : bigbeeconsultants.co.uk/light-http-client Ich habe auch die Dokumentation erweitert.
Rick-777
1

Warum nicht Apache HttpComponents verwenden ? Hier finden Sie häufig gestellte Fragen zur Anwendung , die eine Vielzahl von Szenarien abdecken.

Brian Agnew
quelle
1
Ich kann es benutzen, aber ich wäre glücklicher, ein idiomatischeres Werkzeug zu lernen
Andrea
1

Ich musste dasselbe tun, um einen Endpunkt zu testen (im Integrationstest). Es folgt der Code zum Abrufen der Antwort von der GET-Anforderung in Scala. Ich verwende scala.io.Source, um vom Endpunkt und ObjectMapper für die Konvertierung von JSON in Objekt zu lesen.

private def buildStockMasterUrl(url:String, stockStatus:Option[String]) = {
      stockStatus match  {
        case Some(stockStatus) => s"$url?stockStatus=${stockStatus}"
        case _ => url
    }
  }

    private def fetchBooksMasterData(stockStatus:Option[String]):  util.ArrayList[BooksMasterData] = {
    val url: String = buildBooksMasterUrl("http://localhost:8090/books/rest/catalogue/booksMasterData",stockStatus)
    val booksMasterJson : String = scala.io.Source.fromURL(url).mkString
    val mapper = new ObjectMapper()
    apper.readValue(booksMasterJson,classOf[util.ArrayList[BooksMasterData]])
}

case class BooksMasterData(id:String,description: String,category: String)

Und hier ist meine Testmethode dafür

test("validate booksMasterData resource") {
    val booksMasterData = fetchBooksMasterData(Option(null))
    booksMasterData.size should be (740)
  }
Sanjay Bharwani
quelle
0

Hier ist eine Klasse, an der ich gearbeitet habe. Es hat sowohl GET- als auch POST-Anforderungen. GET ohne Parameter - POST mit Parametern Ich habe es verwendet, um mit StreamSets zu kommunizieren, um eine Pipeline zu starten oder einen Pipeline-Status zu überprüfen.

Es benötigt nur die folgende Abhängigkeit in der Datei build.sbt:

libraryDependencies += "org.scalaj" %% "scalaj-http" % "2.3.0"

Die Dokumentation finden Sie hier: https://github.com/scalaj/scalaj-http#post-raw-arraybyte-or-string-data-and-get-response-code


import scala.collection.mutable.ArrayBuffer
import scalaj.http.{Http, HttpResponse}

object HttpRequestHandler {

  val userName: String = "admin"
  val password: String = "admin"

  def sendHttpGetRequest(request: String): String = {

    println(" Send Http Get Request (Start) ")

    try {

      val httpResponse: HttpResponse[String] = Http(request).auth(userName,password)
                                                            .asString

      val response = if (httpResponse.code == 200) httpResponse.body
      else{
        println("Bad HTTP response: code = "+httpResponse.code )
        return "ERROR"
      }

      println(" Send Http Get Request (End) ")

      return response

    } catch {
      case e: Exception => println("Error in sending Get request: "+e.getMessage)
        return "ERROR"
    }


  }

  def arrayBufferToJson(params:ArrayBuffer[(String,String)]): String ={

    var jsonString = "{"
    var count: Int = 0
    for(param <- params){
      jsonString+="\""+param._1+"\":\""+param._2+"\""+ ( if(count!=params.length-1) "," else "")
      count+=1
    }
    jsonString+="}"

    return jsonString

  }

  def sendHttpPostRequest(request: String,params: ArrayBuffer[(String,String)]): String = {

    println(" Send Http Post Request (Start) ")

    try {
      val postData : String = arrayBufferToJson(params)
      println("Parameters: "+postData)
      val httpResponse: HttpResponse[String] = Http(request).auth(userName,password)
                                                            .header("X-Requested-By","sdc")
                                                            .header("Content-Type", "application/json;charset=UTF-8")
                                                            .header("X-Stream" , "true")
                                                            .header("Accept", "application/json")
                                                            .postData(postData.getBytes)
                                                            .asString


      val response = if (httpResponse.code == 200) httpResponse.body
      else{
        println("Bad HTTP response: code = "+httpResponse.code )
        "ERROR"
      }

      println(" Send Http Post Request (End) ")

      return response

    } catch {
      case e: Exception => println("Error in sending Post request: " + e.getMessage)
        return "ERROR"
    }
  }

}

Abdelrahman Aly
quelle