A Play WS é uma poderosa biblioteca de clientes HTTP, originalmente desenvolvida pelo time de jogo para uso com a estrutura de play. Ele usa o ASYNCHTTPCLIENT para a funcionalidade do cliente HTTP e não possui dependências de reprodução.
Fornecemos alguma documentação aqui sobre como usar o Play WS em seu aplicativo (sem jogo). Para obter mais informações sobre como usar o Play WS em jogo, consulte a documentação da reprodução.
Para começar, você pode adicionar play-ahc-ws-standalone
como uma dependência no SBT:
bibliotecaDependências += "org.playframework" %% "play-ahc-ws-standalone" % "Último " %" last_version "independente"
Onde você substitui LATEST_VERSION
pela versão mostrada nesta imagem :.
Isso adiciona a versão independente do Play WS, apoiada por AsynchttpClient. Esta biblioteca contém as APIs Scala e Java, em play.api.libs.ws
e play.libs.ws
Para adicionar suporte ao XML e JSON usando o Play-Json ou Scala XML, adicione o seguinte:
bibliotecaDependências += "org.playframework" %% "play-ws-standalone-xml" % playwsstandaloneversion LibraryDependências += "Org.PlayFramework" %% "Play-WS-Standalone-Json" % PlayWsStandaloneVersion // Antes da versão 3.0.0: LibraryDependências += "com.typeSafe.play" %% "play-standalone-xml" % playwsstandaloneversion bibliotecaDependências += "com.typesafe.play" %% "play-ws-smandalone-json" % playwsstandaloneversion
O PLAY WS usa versões sombreadas de sinalização de assínchttpclient e oauth, reembalado sob a play.shaded.ahc
e play.shaded.oauth
nomes de pacotes, respectivamente. Shading AsynchttpClient significa que a versão da Netty usada por trás do AsynchttpClient é completamente independente do aplicativo e é de reprodução como um todo.
Especificamente, o Shading AsynchttpClient significa que não há conflitos de versão introduzidos entre o Netty 4.0 e o Netty 4.1 usando o Play WS.
Nota : Se você estiver desenvolvendo play-ws e publicando
shaded-asynchttpclient
eshaded-oauth
usandosbt publishLocal
, você precisa estar ciente de que a atualização~/.ivy2/local
não substitui~/.ivy2/cache
e assim você não verá Seu código sombreado atualizado até você removê -lo do cache. Consulte http://eed3si9n.com/field-test para obter mais detalhes. Este bug foi arquivado como SBT/SBT#2687.
Como reproduza o WS Shades AsynchttpClient, as configurações padrão também são sombreadas e, portanto, não aderem à documentação do AHC. Isso significa que as configurações em ahc-default.properties
e as propriedades do sistema AsynchttpClient são antecipadas com play.shaded.ahc
, por exemplo, a configuração usePooledMemory
na versão sombreada do AsynchttpClient é definida assim:
play.shaded.ahc.org.asynchttpclient.UsepooledMemory = true
O sistema de tipos no Play-WS mudou para que o corpo da solicitação e o corpo de resposta possam usar tipos mais ricos.
Você pode definir sua própria empresa de corpo ou lindável, mas se deseja usar o padrão das configurações da caixa, poderá importar os mapeamentos de tipo com os padrões de linha padrão / padrões padrão.
importar play.api.libs.ws.defaultbodyreadables._import play.api.libs.ws.defaultbodywritables._
É mais provável que você deseje o suporte XML e JSON:
importar play.api.libs.ws.xmlbodyreadables._import play.api.libs.ws.xmlbodywritables._
ou
importar play.api.libs.ws.jsonbodyreadables._import play.api.libs.ws.jsonbodywritables._
Para usar um lindável no corpo em uma resposta, você deve digitar a resposta explicitamente:
importar scala.concurrent. {ExecutionContext, futuro} importar play.api.libs.ws.standalonewsclientImport play.api.libs.ws.xmlbodyReadables._ // NececutionDef HandlexML (WS: StandaloneWSclient) (implícito ec: ExecutionContext): Future: .xml.Elem] = ws.url ("..."). get (). mapa {resposta => resposta.body [scala.xml.elem] }
Ou usando o Play-Json:
importar scala.concurrent. {ExecutionContext, futuro} importar play.api.libs.json.jsvalueimport play.api.libs.ws.standalonewsclientimport play.api.libs.ws.jsonbodyreadables._ // requerirdef HandlejsonResp (WS: StandalOne EC implícito: ExecutionContext): Future [JSValue] = ws.url ("..."). get (). mapa {resposta => resposta.body [jsvalue] }
Observe que há um caso especial: quando você está transmitindo a resposta, deve obter o corpo como fonte:
import scala.concurrent.ExecutionContextimport org.apache.pekko.util.ByteStringimport org.apache.pekko.stream.scaladsl.Sourceimport play.api.libs.ws.StandaloneWSClientdef useWSStream(ws: StandaloneWSClient)(implicit ec: ExecutionContext) = ws.url ("..."). Stream (). mapa {Response => Val Fonte: Source [bytestring, _] = Response.bodyassource val _ = fonte // Faça algo com fonte }
Para postar, você deve passar em um tipo que tenha um mapeamento de classe implícito de BodyWrity:
importar scala.concurrent.executionContextImport play.api.libs.ws.defaultbodywritables._ // requerirdef PostExamlestring (ws: play.api.libs.ws.StandalonewSclient) (Ec implícito: ExecutionContext) = {vald stringdata = Helloworn) (Ec: ExecutionContext) = {val Stringdata = Helloworn) ws.url ("..."). post (stringdata) .map {resposta => / * faça algo * /} }
Você também pode definir sua própria leitura de corpo personalizada:
Importar play.api.libs.ws.BodyReadableImport play.api.libs.ws.ahc.standaloneahcWsResponsecase classe foo (corpo: string) implícito vale foobodyreadable = corpo -leitura [foo] {resposta => importar play.shaded.ahc.org.asynchttpclient. {Response => ahcResponse} val ahcroSponse = Response.asInsinStanceOf [StandaloneahcwsResponse]. Substituindo [ahcroSponse] Foo (ahcroplose.getResponsebody) }
ou escritor de corpo personalizado:
importar org.apache.pekko.util.bytestringimport play.api.libs.ws. {BodyWrity, inMemorybody} implícito val writeableof_foo: BodyWritable [foo] = {// https://tools.ietf.org/html/rfc68883830h/tools.ietf.org/html/rfc68883838383830 -3.2 BodyWrity (foo => inMemorybody (bytestring.FromString (foo.toString)), "Application/vnd.company.category+foo") }
Para usar os mapeamentos de tipo padrão em Java, você deve usar o seguinte:
importar play.libs.ws.defaultbodyReadables; importar play.libs.ws.defaultbodywritables;
seguido pela:
A classe pública myclient implementa o defaultbodywritables, o defaultBodyReadables {public conclusionstage <string> Dosfuff () {return client.url ("http://example.com") .Post (Body ("Hello World")). ThenApply (resposta -> resposta .Body (String ()) ); } }
Observe que há um caso especial: quando você estiver usando um fluxo, deve obter o corpo como fonte:
classe myclass {public conclipiStage <fonte <bytestring, notused >> readResponsasStream () {return ws.url (url) .stream (). thenapply (resposta -> resposta.bodyassource () ); } }
Você também pode postar uma fonte:
classe myclass {public conclussstage <string> Dosfuff () {fonte <bytestring, notused> fonte = fromsource (); retorna ws.url (url) .post (corpo (fonte)). thenapply (resposta -> resposta.body () ); } }
Você pode definir um BodyReadable
CULTIMENTO LILTE:
importar play.libs.ws.ahc. getunderlying (); retorna foo.serialize (ahcroSponse.getResponseBody (standardcharsets.utf_8)); } }
Você também pode definir seu próprio BodyWritable
personalizado:
public class MyClient {Private BodyWritable <String> AlgunseThethod (String String) {org.apache.pekko.util.bytestring bytestring = org.apache.pekko.util.bytestring.FromString (String); retornar new defaultbodywritables.inmemorybodywritable (bytestring, "text/plana"); } }
O cliente independente precisa de Pekko para lidar com dados de streaming internamente:
Em Scala, a maneira de chamar um serviço da web e fechar o cliente:
pacote playwsclientimport org.apache.pekko.actor.actorsystemimport org.apache.pekko.stream._import play.api.libs.ws._import play.api.libs.ws.ahc._import scala.concurrent.futureObjectEbjent {Importagem _ importar scala.concurrent.executionContext.implicits._ def main (args: Array [string]): unit = {// Crie o sistema pekko para thread e streaming de gerenciamento de valit Val = atorsystem () System.ReGisterOnMinMinEmination {System.exit (0) } Materializador implícito do Val = SystemMaterializer (System) .Materializer // Crie o cliente WS independente // Nenhum argumento padrão para um AHCWSClientConfig criado a partir de // "ahcwsclientConfigFactory.forconfig (ConfigFactory.Lload, this.etClass.getClassLoader)" ValwsLe () CHAMADA (WSCLIENT) .e then {case _ => wsclient.close ()} .e then {case _ => system.terminate ()} } defl lall (wSclient: StandaloneWSclient): Future [Unit] = { wsclient.url ("http://www.google.com") .get (). map {resposta => val statustext: string = resposta.statustext val body = resposta.body [string] println (s "obteve uma resposta $ statustext: $ body") } } }
Você também pode criar o cliente independente diretamente a partir de uma instância de AsynchttpClient:
Objeto escalacliente {def main (args: Array [string]): unit = {// use importar play.shaded.ahc.org.asynchttpclient._val asynchttpclientConfig = novo defaultasynchttpclientClientCig.Builder () .SetMaxRequestRetty (0) .SetshutdownEquietperiod (0) .SetshutdownTimeout (0) .BuildVal AsynchttpClient = new DefaultAsynchttpClient (asynchttpclientConfig) val wsclient = new Standaloneahcwsclient (asynchttpclient) /// ... } }
Isso é útil quando existe uma opção de configuração de assínchttpclient que não está disponível na camada de configuração WS.
Em Java, a API é praticamente a mesma:
pacote playwsclient; importar org.apache.pekko.actor.actorsystem; importar org.apache.pekko.stream.*; importar com.typesafe.config.configfactory; importar play.libs.ws.*; importar play.libs.ws.. Ahc. Actorsystem.Create (Nome); System.RegisterOnMinMinEmination (() -> System.Exit (0)); Materializer Materializer = SystemMaterializer.get (System) .Materializer (); // Crie o cliente WS a partir do `Application.conf` arquivo de classe atual e materializer.standaloneahcwsclient ws = standaloneahcwsclient.create (ahcwsclientConfigFactory.forconfig (configFactory.load (), javacient.getclass (). getclass (), materializador); javacient javacient.getclass (). javaclient.run (); } Javaclient (sistema atorsystem, standaloneahcwsclient client) {this.system = system; this.client = client; } public void run () {client.url ("http://www.google.com") .get () .WEncomplete ((Response, Throwable) -> {String statustext = Response.getStatustext (); String body = Response.getBody (String ()); System.out.println ("obteve uma resposta" + statustext); }) .Thenrun (() -> {tente {client.close (); } catch (Exceção e) {e.printStackTrace (); } }) .Thenrun (System :: encerrar); } }
Da mesma forma, você pode fornecer o cliente ASYNCHTTPCLIENT explicitamente da configuração:
public class Javaclient implementa o padrãoBodyReadables {public static void main (string [] args) {// ... // configure asynchttpclient diretamente a partir de configasynchttpclientClientClientClientClientClientClientClientClientClientClientClientCuilder () .SetMaxRequestRetty (0) .SetshutdownEquietperiod (0) .SetShutDownTimeout (0) .build (); assynchttpclient asynchttpclient = new defaultAsynchttpClient (asynchttpclientConfig); // Configure a instância do WSCLIENT diretamente de AsynchttpClient.wsclient client = new ahcwsclient (asynchttpclient, materializador); // ...} }
Jogar WS implementa o cache HTTP através do CachingAsynchttpClient, Ahchttpcache e CacheControl, uma biblioteca mínima de gerenciamento de cache HTTP em Scala.
Para criar um cliente AHC independente que usa cache, passe em uma instância de AHCHTTPCACHE com um adaptador de cache para a implementação subjacente. Por exemplo, para usar a cafeína como cache subjacente, você pode usar o seguinte:
import scala.concurrent.Futureimport java.util.concurrent.TimeUnitimport com.github.benmanes.caffeine.cache.{ Caffeine, Ticker }import play.api.libs.ws.ahc.StandaloneAhcWSClientimport play.api.libs.ws.ahc. cache. {Ahchttpcache, cache, eficácia, ResponseEntry} classe Caffeinehttpcache estende o cache {Val subjacente = cafeine.newbuilder () .Ticker (ticker.systemTicker ()) .ExpireAxtwrite (365, timeUnit.days) .Build [effectionurikey, ResponseEntry] () def remover (chave: effectionurikey) = futuro.successful (opção (subjacente.invalidate (key)) def Put (chave: eficaz, entrada: entrada: resposta) = futura.successful (subjacente.put.put.put.put (chave, entrada)) def get (chave: eficaz) = futuro.successful (opção (zagueiro subjacente getifpresent)) def feche (): unit = subjacente.cleanup () }def withCache(implicit m: org.apache.pekko.stream.Materializer): StandaloneAhcWSClient = { implicit def ec = m.executionContext val cache = new CaffeineHttpCache() StandaloneAhcWSClient(httpCache = Some(new AhcHttpCache(cache))) }
Existem vários guias que ajudam a montar cabeçalhos de controle de cache:
Guia de Mozilla para cache HTTP
Guia de Mark Nottingham para armazenar em cache
Cache http
Descanse fácil: cache http
Consulte https://github.com/playframework/.github/blob/main/releasing.md
O PLAY WS é licenciado sob a licença do Apache, versão 2. Consulte o arquivo de licença para obter mais informações.