Play WS est une puissante bibliothèque client HTTP, développée à l'origine par l'équipe de jeu pour une utilisation avec Play Framework. Il utilise AsynchTTTPClient pour la fonctionnalité du client HTTP et n'a pas de dépendances de jeu.
Nous avons fourni ici une documentation sur la façon d'utiliser Play WS dans votre application (sans jeu). Pour plus d'informations sur la façon d'utiliser Play WS en jeu, veuillez vous référer à la documentation de jeu.
Pour commencer, vous pouvez ajouter play-ahc-ws-standalone
comme dépendance dans SBT:
LibraryDependances + = "org.PlayFramework" %% "play-ahc-ws-standalone"% "Dermter_version" // Avant la version 3.0.0: LibraryDependces + = "com.typesafe.play" %% "play-ahc-ws- "%" DERNIER_VERSION "
Où vous remplacez LATEST_VERSION
par la version indiquée dans cette image :.
Cela ajoute la version autonome de Play WS, soutenue par asynchttpclient. Cette bibliothèque contient à la fois les API Scala et Java, sous play.api.libs.ws
et play.libs.ws
Pour ajouter le support XML et JSON à l'aide de Play-Json ou Scala XML, ajoutez ce qui suit:
LibraryDependances + = "org.playFramework" %% "play-ws-standalone-xml"% playwsstandaloneversion LibraryDependances + = "org.PlayFramework" %% "play-ws-standalone-json"% playwsstandaloneVeversion // Avant la version 3.0.0: LibraryDependces + = "com.typesafe.play" %% "play-ws-standalone-xml" % playwsstandaloneversion LibraryDependances + = "com.typesafe.play" %% "play-ws-standalone-json"% playwsstandaloneversion
Play WS utilise des versions ombragées d'AsynchttpClient et OAuth SignPost, reconditionnées sous les noms play.shaded.ahc
et play.shaded.oauth
, respectivement. L'ombrage asynchttpclient signifie que la version de Netty utilisée derrière asynchttpclient est complètement indépendante de l'application et joue dans son ensemble.
Plus précisément, l'ombrage asynchttpclient signifie qu'il n'y a pas de conflits de version introduits entre Netty 4.0 et Netty 4.1 à l'aide de Play WS.
Remarque : Si vous développez des play-ws et publiez
shaded-asynchttpclient
etshaded-oauth
à l'aidesbt publishLocal
, vous devez savoir que la mise à jour~/.ivy2/local
ne remplace pas~/.ivy2/cache
et donc vous ne verrez pas Votre code ombré mis à jour jusqu'à ce que vous le supprimez du cache. Voir http://eed3si9n.com/field-test pour plus de détails. Ce bogue a été déposé en SBT / SBT # 2687.
Parce que jouer WS Shades AsynchttpClient, les paramètres par défaut sont également ombrés et n'adhèrent donc pas à la documentation AHC. Cela signifie que les paramètres dans ahc-default.properties
et les propriétés du système asynchttpclient sont admissibles avec play.shaded.ahc
, par exemple le paramètre usePooledMemory
dans la version ombragée d'AsynchttpClient est défini comme ceci:
play.shaded.ahc.org.asynchttpclient.usepooledMemory = true
Le système de type dans Play-WS a changé afin que le corps de demande et le corps de réponse puissent utiliser des types plus riches.
Vous pouvez définir votre propre corpswitable ou corporel, mais si vous souhaitez utiliser les paramètres par défaut de la boîte, vous pouvez importer les mappages de type avec les DaultBodyRedables / DefaultBodyWritables.
import play.api.libs.ws.defaultbodyreadables._import play.api.libs.ws.defaultbodywritables._
Plus probablement, vous voudrez le support XML et JSON:
import play.api.libs.ws.xmlbodyreadables._import play.api.libs.ws.xmlbodywritables._
ou
import play.api.libs.ws.jsonbodyreadables._import play.api.libs.ws.jsonbodywritables._
Pour utiliser un body-lisable dans une réponse, vous devez taper la réponse explicitement:
Importer scala.concurrent. {ExecutionContext, futur} import play.api.libs.ws.standalonewsclientImport play.api.libs.ws.xmlbodyreadables._ // requisDef handlexml (ws: standalonewsclient) (Implicit EC: EXECUMENTCONT): Future [scala Scala .xml.elem] = ws.url ("..."). get (). map {réponse => réponse.body [scala.xml.elem] }
ou en utilisant Play-Json:
Importer scala.concurrent. {ExecutionContext, futur} import play.api.libs.json.jsvaluemport play.api.libs.ws.standalonewsclientImport play.api.libs.ws.jsonBodyReadables._ // requiredDef handlejsonresp (ws: standalonewsclient) ( Implicit EC: ExecutionContext): futur [jsvalue] = ws.url ("..."). get (). map {réponse => réponse.body [jsvalue] }
Notez qu'il existe un cas spécial: lorsque vous diffusez la réponse, vous devriez obtenir le corps comme source:
Importer scala.concurrent.executionContextImport org.apache.pekko.util.bytestrimport org.apache.pekko.stream.scaladsl.sourceImport play.api.libs.wsclient). ws.Url ("..."). Stream (). Map {réponse => Val Source: Source [ByTesTring, _] = Response.BodyAssource Val _ = Source // faire quelque chose avec Source }
Pour publier, vous devez passer dans un type qui a une cartographie de classe implicite de Bodywitable:
Importer scala.concurrent.executionContextImport play.api.libs.ws.defaultbodywritables._ // requireddef postExamplestring (ws: play.api.libs.ws.standalonewsclient) (Implicit ec: ExecutionContext) = {val stringdata = "Hello World" ws.url ("..."). Post (stringData) .map {réponse => / * faire quelque chose * /} }
Vous pouvez également définir votre propre corporelable personnalisée:
import play.api.libs.ws.bodyReadableImport play.api.libs.ws.ahc.standaloneAhcwsResponseCase class foo (body: string) implicit val foobodyreadable = bodyreadable [foo] {réponse => import play.shaded.ahc.org.asynchttpclient. {réponse => ahcrosponse} val ahcrosponse = réponse.asinstanceof [standaloneAhcwsResponse]. }
ou corporel personnalisé:
import org.apache.pekko.util.bytestrimport play.api.libs.ws. {bodywitable, inmemorybody} implicite val writeablef_foo: bodywitable [foo] = {// https://tools.ietf.org/html/rfc6838#Section -3.2 Bodywitable (foo => inmemorybody (bytestring.fromstring (foo.tostring)), "application / vnd.company.category + foo") }
Pour utiliser les mappages de type par défaut en Java, vous devez utiliser ce qui suit:
import play.libs.ws.defaultBodyReadables; import play.libs.ws.defaultbodywritables;
suivi de:
classe publique MyClient implémente defaultBodyWritables, defaultBodyReadables {public E complétionstage <string> dostuff () {return client.url ("http://example.com") .post (body ("hello world")). .Body (String ()) )); } }
Notez qu'il existe un cas spécial: lorsque vous utilisez un flux, vous devriez obtenir le corps comme source:
class myClass {public E complétionStage <source <bytestring, notationd >> readResponSestStream () {return ws.url (url) .stream (). thereApply (réponse -> réponse.bodyAssource () )); } }
Vous pouvez également publier une source:
class myClass {public E complétionstage <string> dostuff () {source <byTestring, notutilisé> source = fromsource (); return ws.url (url) .post (body (source)). thenApply (réponse -> réponse.body () )); } }
Vous pouvez définir un BodyReadable
personnalisé:
Importer play.libs.ws.ahc. *; import play.shaded.ahc.org.asynchttpclient.Response; class Fooradable implémente bodyreadable <standalonewsResponse, foo> {public foo appliquent (standalonewsResesponse réponse) {réponse ahcresponse = (réponse) Réponse. getUnderlying (); return foo.serialize (ahcrosponse.getResponseBody (standardCharsets.utf_8)); } }
Vous pouvez également définir votre propre BodyWritable
personnalisé:
classe publique myClient {private bodywitable <string> SomeotherMethod (String String) {org.apache.pekko.util.bytestring byTestring = org.apache.pekko.util.bytestring.fromstring (string); return new defaultBodyWritables.InMemoryBodyWitable (bytestring, "text / plain"); } }
Le client autonome a besoin de Pekko pour gérer les données de streaming en interne:
Dans Scala, la façon d'appeler un service Web et de fermer le client:
Package PlaywsclientImport org.apache.pekko.actor.ACTORSYSTEMIMPORT org.apache.pekko.stream._import play.api.libs.ws._import play.api.libs.ws.ahc._import scala.concurrent.futureObject ScalaGlient {importebodyRebodyRedables. _ importer scala.concurrent.executionContext.implicites._ def main (args: array [string]): unit = {// créer un système pekko pour le thread et le streaming management implicit system = ActorSystem () System.Registerontermination {System.exit (0) } Implicit Val Materializer = SystemMaterializer (System) .materializer // Créer le client WS autonome // Aucun argument par défaut ne fait par défaut qu'un AHCWSClientConfig créé à partir de // "AHCWSCLIENTCONFIGFACTORY.FORCONFIG (configFactory.load, this.getClass.getClassload)" Val wsclient = standalonhcwcwsclient () Appel (wsclient) .AndThen {cas _ => wsclient.close ()} .AndThen {cas _ => System.terminate ()} } Def Call (wsclient: standalonewsclient): futur [unité] = { wsclient.url ("http://www.google.com") .get (). map {réponse => val statustext: string = réponse.statustext val body = réponse.body [string] println (S "Got a Response $ Statustext: $ body") } } }
Vous pouvez également créer le client autonome directement à partir d'une instance asynchttpclient:
objet scalaclient {def main (args: array [string]): unit = {// utilise l'importation play.shaded.ahc.org.asynchttpclient._val asynchttpclientconfig = new defaultasynchttpclientconfig.builder () .SetMaxRequestretry (0) .setShutdownquietperiod (0) .setShutdownTimeout (0) .buildVal asynchttpClient = new defaultAsynchttpClient (asynchttpclientConfig) val wsclient = new standaloneAhcwsclient (asynchttpclient) /// ... } }
Ceci est utile lorsqu'il existe une option de configuration asynchttpclient qui n'est pas disponible dans la couche de configuration WS.
Dans Java, l'API est à peu près la même:
package playwsclient; import org.apache.pekko.actor.actorsystem; import org.apache.pekko.stream. *; import com.typesafe.config.configfactory; import play.libs.ws. *; import play.libs.ws. AHC. *; Classe publique Javaclient implémente defaultBodyReadables {Client privé standaloneAhcwsClient; Système privé ActorSystem; public static void main (String [] args) {// configuration de la matérializer Pekko pour gérer le streamingFinal String name = "wsclient"; acteursystem System = System = ActorSystem.Create (name); System.RegisterOnTermination (() -> System.Exit (0)); Materializer Materializer = SystemMaterializer.get (System) .Materializer (); // Créer le client WS à partir de `application.conf` Fichier, le Classloader actuel et Materializer.StandalOneAhcwsClient WS = StandalOneAHCWSClient.Create (AHCWSClientConfigFactory.forconfig (configFactory.load (), System.getClass (). GetClassLoader ()), Materializer); Javaclient Javaclient = New Javaclient (Système); javaclient.run (); } Javaclient (Système ActorSystem, standalonEAHCWSClient client) {this.system = System; this.client = client; } public void run () {client.url ("http://www.google.com") .get () .Cencomplete ((Response, Throwable) -> {String StatusText = Response.getStatUsText (); String Body = Response.getBody (String ()); System.out.println ("Got a Response" + StateStExt); }) .ThenRun (() -> {try {client.close (); } catch (exception e) {e.printStackTrace (); } }) .TheNrun (Système :: Terminer); } }
De même, vous pouvez fournir le client asynchttpclient explicitement à partir de la configuration:
La classe publique Javaclient implémente defaultBodyReadables {public static void main (String [] args) {// ... // configure asynchttpclient directement à partir de configasynchttpclientconfig asynchttpclientconfig = new defaultAnchtttpclientConfig.builder () .SetMaxRequestretry (0) .setShutdownquietperiod (0) .setShutdownTimeout (0) .build (); asynchttpclient asynchttpclient = new defaultasynchttpclient (asynchttpclientConfig); // Configuration de l'instance WSClient directement à partir d'asynchttpclient.wsclient client = new AHCWSClient (asynchttpclient, matérialiser); // ...} }
Play WS implémente la mise en cache HTTP via CachingasynchttpClient, Ahchttpcache et CacheControl, une bibliothèque de gestion de cache HTTP minimale à Scala.
Pour créer un client AHC autonome qui utilise la mise en cache, passez dans une instance d'AhchttpCache avec un adaptateur de cache à l'implémentation sous-jacente. Par exemple, pour utiliser la caféine comme cache sous-jacent, vous pouvez utiliser ce qui suit:
Importer scala.concurrent.futuremport java.util.concurrent.timeUnitimport com.github.benmanes.caffeine.cache. {Caffeine, Ticker} import play.api.libs.ws.ahc.ahcc. cache. {ahchttpcache, cache, effectiveUrikey, réponse} class caaffeinehttpcache étend le cache {val sous-jacent = caféine.newbuilder () .Ticker (Ticker.SystemTicker ()) .expirefterWrite (365, timeUnit.Days) .build [effectiveUrikey, Responsentry] () def supprimer (clé: effectiveUrikey) = future.successful (option (sous-jacent.invalidate (clé))) def put (clé: efficace, entrée: réponse) = futur.successful (sous-lin (clé, entrée)) def get (clé: effectiveUrikey) = futur.successful (option (clé Getifpresent sous-jacente)) def clôture (): unité = sous-jacent.cleanup () } def withcache (implicite m: org.apache.pekko.stream.materializer): standaloneAhcwsClient = {implicit def ec = m.executionContext val cache = new CaffeineHttpCache () standaloneahcwsclient (httpcache = some (new ahchttpcache (cache)))) }
Il existe un certain nombre de guides qui aident à assembler des en-têtes de contrôle du cache:
Guide de Mozilla à la mise en cache HTTP
Guide de la mise en cache de Mark Nottingham
Cache HTTP
Repos facile: cache http
Voir https://github.com/playframework/.github/blob/main/releason.md
Play WS est concédé sous licence Apache, version 2. Voir le fichier de licence pour plus d'informations.