Play WS es una poderosa biblioteca de clientes HTTP, desarrollada originalmente por el equipo de juegos para usar con el marco de juego. Utiliza AsynchttpClient para la funcionalidad del cliente HTTP y no tiene dependencias de juego.
Hemos proporcionado algo de documentación aquí sobre cómo usar WS WS en su aplicación (sin reproducción). Para obtener más información sobre cómo usar PLAY WS en el juego, consulte la documentación de juego.
Para comenzar, puede agregar play-ahc-ws-standalone
como dependencia en SBT:
LibraryDependences += "org.playframework" %% "Play-ahc-ws-standalone" % "ortat_version" // antes de la versión 3.0.0: bibliotecadependencias += "com.typesafe.play" %% "play-ahc-ws- independiente " %" ortat_version "
Donde reemplaza LATEST_VERSION
con la versión que se muestra en esta imagen :.
Esto agrega la versión independiente de Play WS, respaldada por AsynchttpClient. Esta biblioteca contiene las API de Scala y Java, bajo play.api.libs.ws
y play.libs.ws
Para agregar soporte XML y JSON usando Play-Json o Scala XML, agregue lo siguiente:
LibraryDependencies += "org.playframework" %% "Play-WS-Standalone-xml" % PlaywsStandalonversion LibraryDependences += "org.playframework" %% "Play-ws-standalone-json" % playwsstandaloneversion // antes de la versión 3.0.0: bibliotecadependences += "com.typesafe.play" %% "play-standalone-xml" " % PlaywsStandaloneVersion LibraryDependencies += "com.typesafe.play" %% "Play-ws-standalone-json" % PlaywsStandalonversion
Play WS utiliza versiones sombreadas de AsynchttpClient y Oauth SignPost, reempaquetado bajo el play.shaded.ahc
y play.shaded.oauth
nombres de paquetes, respectivamente. Shading AsynchttpClient significa que la versión de Netty utilizada detrás de AsynchttpClient es completamente independiente de la aplicación y juega en su conjunto.
Específicamente, sombrear AsynchttpClient significa que no hay conflictos de versión introducidos entre Netty 4.0 y Netty 4.1 usando PLAY WS.
Nota : Si está desarrollando Play-WS y publicando
shaded-asynchttpclient
yshaded-oauth
utilizandosbt publishLocal
, debe tener en cuenta que la actualización~/.ivy2/local
no sobrescribe~/.ivy2/cache
y, por lo tanto, no verá que no verá Su código sombreado actualizado hasta que lo elimine del caché. Consulte http://eed3si9n.com/field-test para más detalles. Este error se ha presentado como SBT/SBT#2687.
Debido a que Play WS Shades AsynchttpClient, la configuración predeterminada también está sombreada y, por lo tanto, no se adhiera a la documentación AHC. Esto significa que la configuración en ahc-default.properties
y las propiedades del sistema AsynchttpClient se preparan con play.shaded.ahc
, por ejemplo, la configuración usePooledMemory
en la versión sombreada de AsynchttpClient se define así:
Play.shaded.ahc.org.asynchttpclient.UsepooledMemory = True
El sistema de tipos en Play-WS ha cambiado para que el cuerpo de solicitud y el cuerpo de respuesta puedan usar tipos más ricos.
Puede definir su propio bodywritable o reemplazable, pero si desea utilizar la configuración predeterminada fuera de la caja, puede importar las asignaciones de tipo con el valor predeterminado / defaultishBodyWritables.
Import Play.api.libs.ws.defaultBodyBodyable._import Play.api.libs.ws.defaultBodyWritables._
Lo más probable es que desee el soporte XML y JSON:
import play.api.libs.ws.xmlbodyreadables._import Play.api.libs.ws.xmlbodywritables._
o
Importar Play.api.libs.ws.jsonBodyLeadables._import Play.api.libs.ws.jsonbodywritables._
Para usar un cuerpo reemplazable en una respuesta, debe escribir la respuesta explícitamente:
import escala.concurrent. {EjecutionContext, Future} import Play.api.libs.ws.standalonewsclientimport Play.api.libs.ws.xmlbodyables._ // requerido handlexml (ws: standalonewsclient) (implícite eC: ejecutionContext): futuro [Scalaa .xml.elem] = ws.url ("..."). get (). map {respuesta => respuesta.body [scala.xml.elem] }
o usar Play-Json:
import scala.concurrent. {EjecutionContext, Future} import Play.api.libs.json.jsvalueImport Play.api.libs.ws.standalonewsclientimport Play.api.libs.ws.jsonBodyBodyable._ // requerido Handef HandleJsonResp (WS: StandaloneWSclient) (( implícita EC: ejecutionContext): Future [JSValue] = ws.url ("..."). get (). map {respuesta => respuesta.body [jsValue] }
Tenga en cuenta que hay un caso especial: cuando está transmitiendo la respuesta, debe obtener el cuerpo como fuente:
import scala.concurrent.ExecutionContextImport org.apache.pekko.util.bytestringimport org.apache.pekko.stream.scaladsl.sourceimport play.api.libs.ws.standalonewsclientdef useWsStream (ws: salas de margen) (implícite ec: ejecutorwsclext) ws.URL ("..."). Stream (). MAP {Respuesta => Val Fuente: Fuente [ByTestring, _] = Response.BodySource Val _ = Fuente // Haz algo con la fuente }
Para publicar, debe pasar un tipo que tenga un mapeo de clase implícito de BodyWritable:
import scala.concurrent.ExecutionContextImport Play.api.libs.ws.defaultBodyWrithables._ // RequiredDef PostExAMPlEnrring (ws: play.api.libs.ws.standalonewsclient) (implícito EC: EjecutionContext) = {val stringData = "Hola World" ws.url ("..."). Post (StringData) .map {Respuesta => / * Do Something * /} }
También puede definir su propio cuerpo personalizado:
import play.api.libs.ws.bodyReadableImport Play.api.libs.ws.ahc.StandaloneahcwsResponseCase Class foo (Body: String) Val implícito FOOBODYREABLE = BodyReadable [foo] {Respuesta => import play.shaded.ahc.org.asynchttpclient. {Respuesta => ahcResponse} val ahcResponse = respuesta.asinstanceof [standaloneahcwsResponse]. }
o el cuerpo personalizado:
importar org.apache.pekko.util.bytestringimport Play.api.libs.ws. {Bodywritable, InMemoryBody} Val implícito WriteableOf_foo: BodyWritable [foo] = {// https://tools.ietf.org/html/rfc6838#section -3.2 Bodywritable (foo => inMemoryBody (bytestring.fromstring (foo.tostring)), "Aplicación/vnd.company.Category+Foo") }
Para usar las asignaciones de tipo predeterminadas en Java, debe usar lo siguiente:
Import Play.libs.ws.defaultBodyBodyLeables; import Play.libs.ws.defaultBodyWritables;
seguido de:
clase pública myClient implementa defaultBodyWritables, defaultBodyLeadables {public SurfutinImentStage <String> dostuff () {return client.url ("http://example.com") .post (body ("hello world")) .dayapply (respuesta -> respuesta .Body (String ()) ); } }
Tenga en cuenta que hay un caso especial: cuando está utilizando una transmisión, debe obtener el cuerpo como fuente:
class myClass {public finalationStage <Source <bytestring, noused >> readResponseSstream () {return ws.URL (url) .stream (). thenapply (respuesta -> respuesta.bodyAsource () ); } }
También puede publicar una fuente:
class myClass {public complementStage <String> dostuff () {Source <byTestring, NotUsed> Source = fromSource (); return ws.URL (url) .post (cuerpo). ); } }
Puede definir un BodyReadable
personalizado:
Import Play.libs.ws.ahc.*; Import Play.shaded.AHC.org.asynchttpclient.Response; clase FOREDABLE implementa BodyReatable <StandalonewsResponse, foo> {public foo Aplication (Respuesta SoldalonewsResponse) {Respuesta AHCRESPONSE = (Respuesta) Respuesta. getunderying (); return foo.serialize (ahcresponse.getResponseBody (StandardCharSets.utf_8)); } }
También puede definir su propio BodyWritable
personalizado:
clase pública myClient {private Bodywritable <String> SomeThermethod (String String) {org.apache.pekko.util.bytestring bytestring = org.apache.pekko.util.bytestring.fromstring (string); return New DefaultBodyWritables.InMemoryBodyWritable (byTestring, "Text/Plain"); } }
El cliente independiente necesita Pekko para manejar los datos de transmisión internamente:
En Scala, la forma de llamar a un servicio web y cerrar el cliente:
Paquete 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 Scalaclient {importar en defaultislables. _ import scala.concurrent.executionContext.implicits._ Def Main (args: array [string]): unit = {// Crear sistema PEKKO para la gestión de subprocesos y transmisión IMPLÍCITO Val System = ActorSystem () System.RegisterOnmination {System.Exit (0) } implícito val saterterizer = SystemMaterializer (sistema) .Materializer // Cree el cliente WS independiente // ningún argumento predeterminado a un AHCWSClientConfig creado desde // "AHCWSClientConfigFactory.forConfig (configFactory.load, this.getClass.getClassLoader)" Val wsClient = standaloneahcwsclient () llamar (wsclient) .AnyThen {case _ => wsClient.close ()} .ythen {case _ => system.merminate ()} } Def Call (wsclient: standalonewsclient): futuro [unit] = { wsclient.url ("http://www.google.com") .get (). MAP {Response => val StatusText: String = Response.StatusText Val Body = Response.Body [String] println (S "obtuvo una respuesta $ StatusText: $ Body") } } }
También puede crear el cliente independiente directamente desde una instancia de AsynchttpClient:
Object Scalaclient {def main (args: array [string]): unit = {// use import play.shaded.ahc.org.asynchttpclient._val asynchttpclientconfig = new DefaultSynchttpclientconfig.builder () .SetMaxRequestretry (0) .setshutdownquietperiod (0) .SetShutDownTimeOut (0) .BuildVal AsynchttpClient = new DefaultSynchttpClient (AsynchttpClientConfig) val wsclient = new standaloneAHCWSCLIENT (asynchttpclient) /// ... } }
Esto es útil cuando hay una opción de configuración de AsynchttpClient que no está disponible en la capa de configuración WS.
En Java, la API es muy similar:
paquete 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.*;public class JavaClient implements DefaultBodyReadables {private final StandaloneAhcWSClient client;private final ActorSystem system;public static void main(String[] args) {// Set up Pekko materializer to handle streamingfinal String name = "wsclient";ActorSystem system = Actorsystem.create (name); System.RegisterOnmination (() -> System.Exit (0)); materializer materializador = systemMaterializer.get (sistema) .materializer (); // Cree el cliente WS desde la aplicación.conf` file, the current classloader and materializer.StandaloneAhcWSClient ws = StandaloneAhcWSClient.create(AhcWSClientConfigFactory.forConfig(ConfigFactory.load(), system.getClass().getClassLoader()),materializer);JavaClient javaClient = new JavaClient(system, ws); javaclient.run (); } Javaclient (Sistema ActorSystem, StandaloneAhcwsClient Client) {this.system = system; this.client = client; } public void run () {client.url ("http://www.google.com") .get () .Whencomplete ((Respuesta, Throwable) -> {String StatusText = Response.getStatusText (); String Body = Response.getBody (String ()); System.out.println ("Got a Response" + StatusText); }) .ThenRun ((() -> {try {client.close (); } catch (Exception e) {E.PrintStackTrace (); } }) .thenrun (sistema :: terminado); } }
Del mismo modo, puede proporcionar el cliente AsynchttpClient explícitamente desde la configuración:
clase pública Javaclient implementa defaultBodyLeadables {public static void main (string [] args) {// ... // configure asynchttpclient directamente desde configasynchttpclientconfig asynchttpclientconfig = new Defaultttpclientconfig.builder () .SetMaxRequestretry (0) .setshutdownquietperiod (0) .SetShutDownTimeOut (0) .Build (); asynchttpclient asynchttpclient = new DefaultSynchttpClient (AsynchttpClientConfig); // Configure la instancia de WSClient directamente desde AsynchttpClient.wsClient Client = new AHCWSClient (AsynChttpClient, materializador); // ...} }
Play ws implementa http almacenamiento en caché a través de CachingasynchttpClient, Ahchttpcache y Cachecontrol, una biblioteca mínima de administración de caché HTTP en Scala.
Para crear un cliente AHC independiente que use almacenamiento en caché, pase en una instancia de ahchttpcache con un adaptador de caché a la implementación subyacente. Por ejemplo, para usar la cafeína como caché subyacente, puede usar lo siguiente:
import escala.concurrent.futureImport java.util.concurrent.timeunitimport com.github.benmanes.caffeine.cache. {Caffeine, ticker} import play.api.libs.ws.ahc.standaloneahcwsclaatesport play.api.libs.ws.ahc. Cache. {Ahchttpcache, caché, efectivo de efectivo, respuesta} clase Caffeinehttpcache extiende la caché {val subyacente = Caffeine.newBuilder () .Chicker (Ticker.SystemTicker ()) .Expirante a uno (365, TimeUnit.days) .Build [Effectionurikey, ResponseEntry] () Def Eliminar (Key: EfectiveUrikey) = Future.Successful (Opción (Subyacente.invalidato (Key)) Def Put (Key: EffectionurikeY, Entrada: Respuesta) = Future.successful (subyacente. (clave, entrada)) Def Get (Key: EffectionUrikey) = Future.Successful (opción (Key Key Getifpresent Subyacente)) Def Close (): Unit = Underying.CleanUp () } def withcache (implícito m: org.apache.pekko.stream.materializer): standaloneahcwsClient = {implícito def ec = m.ExecutionContext val cache = new CaffeineHttpCache () standalonEAHCWSCLIEN }
Hay una serie de guías que ayudan a armar los encabezados de control de caché:
Guía de Mozilla para el almacenamiento en caché de HTTP
Guía de Mark Nottingham para almacenar en caché
Http en caché
Descansa fácil: caché http
Ver https://github.com/playframework/.github/blob/main/Releing.md
Play WS tiene licencia bajo la licencia Apache, versión 2. Consulte el archivo de licencia para obtener más información.