Accepter la requête HTTP dans l'application R shiny

j'ai une application brillante que j'ai faite qui a besoin de récupérer ses données d'un autre serveur, c.-à-d. l'autre serveur lorsque l'application brillante est ouverte envoie une requête à l'application brillante pour ouvrir l'application et lui donner les données dont elle a besoin.

Pour simuler cela, je peux vous envoyer les éléments suivants à la R brillant app quand j'ouvre l'application dans firefox:

 http://localhost:3838/benchmark-module/?transformerData=data/TransformerDataSampleForShiny.json

C'est une simple requête get qui envoie la piqûre appelé : "Données Du Transformateur" avec contenu "data / Transformerdataéchantillonforshing.json" à la brillante application.

Lorsque j'utilise le code, il fonctionne très bien:

#(Abridged code, I am only showing the start of the code)
 shinyServer(function(input, output) {
 jsonFile <- "data/TransformerDataSampleForShiny.json"
 JSONdata <- fromJSON(jsonFile)

mais quand je veux faire exactement la même chose sauf que plutôt que le codage dur la chaîne "data/Transformerdataasampleforshiny.json" je veux recevoir cette chaîne de la requête http au-dessus. Comment dois-je faire?? J'ai essayé le code:

shinyServer(function(input, output) {
jsonFile <- input$transformerData
JSONdata <- fromJSON(jsonFile)

et j'ai aussi essayé:

....
jsonFile <- input$TransformerData

mais rien de tout cela n'a fonctionné.

DONC la question principale est: Comment puis-je coder pour recevoir des requêtes HTTP? Je voudrais recevoir des chaînes de caractères à partir de requêtes HTTP GET et / ou de fichiers JSON à partir de requêtes POST.

juste pour clarifier que je ne veux pas envoyer de courrier ou recevoir des demandes de R. Je veux les recevoir. Je ne peux pas utiliser le paquet httr ou le paquet httpRequest pour recevoir

Merci beaucoup!

15
demandé sur James Willcox 2014-08-14 02:50:37

3 réponses

vous pouvez recevoir des requêtes GET en utilisant session$clientData. Un exemple exécute ce qui suit

library(shiny)
runApp(list(
  ui = bootstrapPage(
    textOutput('text')
  ),
  server = function(input, output, session) {
    output$text <- renderText({
      query <- parseQueryString(session$clientData$url_search)
      paste(names(query), query, sep = "=", collapse=", ")
    })
  }
), port = 5678, launch.browser = FALSE)

et naviguez vers

http://127.0.0.1:5678/?transformerData=data/TransformerDataSampleForShiny.json

voir la réponse de @Xin Yin pour une méthode pour exposer les requêtes POST.

13
répondu jdharrison 2016-08-11 23:01:46

la réponse de@jdharrison est une façon de gérer GET demandes dans Brillant. Malheureusement, sa déclaration

shiny ne traite pas les demandes de courrier malheureusement.

n'est pas, à proprement parler, 100% exact.

Vous poignée POST demandes de Shiny avec l'aide de la fonction session$registerDataObj. Un exemple d'utilisation de cette fonction peut être trouvé dans cet exemple,. Au fond, par appel de registerDataObj fonction, elle renvoie un unique demande de l'URL à laquelle vous pouvez lancer GET ou POST demandes. Toutefois, l'exemple ci-dessus ne me semble pas très utile dans le contexte de votre question parce que:

  1. il n'y a pas d'utilisation explicite D'AJAX dans cet exemple. Plutôt, l'exemple exploite registerDataObj pour créer un gestionnaire de fichiers PNG, et il lie directement L'URL au src<img> balise.
  2. Il est encore à l'aide de GET demande POST.

mais, vous pouvez Multiplexer cette fonction pratique pour gérer les deux GET et POST parfaitement bien. Considérons l'exemple suivant:

le serveur.R

library(shiny)

shinyServer(function(input, output, session) {
  api_url <- session$registerDataObj( 
    name   = 'api', # an arbitrary but unique name for the data object
    data   = list(), # you can bind some data here, which is the data argument for the
                     # filter function below.
    filter = function(data, req) {
      print(ls(req))  # you can inspect what variables are encapsulated in this req
                      # environment
      if (req$REQUEST_METHOD == "GET") {
        # handle GET requests
        query <- parseQueryString(req$QUERY_STRING)
        # say:
        # name <- query$name
        # etc...
      } 

      if (req$REQUEST_METHOD == "POST") {
        # handle POST requests here

        reqInput <- req$rook.input

        # read a chuck of size 2^16 bytes, should suffice for our test
        buf <- reqInput$read(2^16)

        # simply dump the HTTP request (input) stream back to client
        shiny:::httpResponse(
          200, 'text/plain', buf
        )
      }          
    }
  )

  # because the API entry is UNIQUE, we need to send it to the client
  # we can create a custom pipeline to convey this message
  session$sendCustomMessage("api_url", list(url=api_url))

})

interface utilisateur.R

library(shiny)

shinyUI(fluidPage(
  singleton(tags$head(HTML(
    '
  <script type="text/javascript">
    $(document).ready(function() {
      // creates a handler for our special message type
      Shiny.addCustomMessageHandler("api_url", function(message) {
        // set up the the submit URL of the form
        $("#form1").attr("action", "/" + message.url);
        $("#submitbtn").click(function() { $("#form1").submit(); });
      });
    })
  </script>
'
  ))),
  tabsetPanel(
    tabPanel('POST request example',
             # create a raw HTML form
             HTML('
<form enctype="multipart/form-data" method="post" action="" id="form1">
    <span>Name:</span>
    <input type="text" name="name" /> <br />
    <span>Passcode: </span> <br />
    <input type="password" name="passcode" /><br />
    <span>Avatar:</span>
    <input name="file" type="file" /> <br />
    <input type="button" value="Upload" id="submitbtn" />
</form>
')
    )
  )
))

maintenant, disons que j'entre ces entrées de test:

Some test input

Puis appuyez sur "Upload", vous soumettez une requête POST au serveur brillant, qui, basé sur notre code R, supprimera le POST de votre navigateur demande de flux pour vous en tant que réponse.

Par exemple, j'obtiens:

------WebKitFormBoundary5Z0hAYXQXBHPTLHs
Content-Disposition: form-data; name="name"

foo
------WebKitFormBoundary5Z0hAYXQXBHPTLHs
Content-Disposition: form-data; name="passcode"

bar
------WebKitFormBoundary5Z0hAYXQXBHPTLHs
Content-Disposition: form-data; name="file"; filename="conductor.png"
Content-Type: image/png

‰PNG


IHDR  X   ¦   5Š_       pHYs  a  a¨?§i  ÕiTXtXML:com.adobe.xmp     <x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="XMP Core 5.1.2">
   <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
      <rdf:Description rdf:about=""
            xmlns:tiff="http://ns.adobe.com/tiff/1.0/">
         <tiff:Compression>5</tiff:Compression>
         <tiff:PhotometricInterpretation>2</tiff:PhotometricInterpretation>
         <tiff:Orientation>1</tiff:Orientation>
      </rdf:Description>
   </rdf:RDF>
</x:xmpmeta>
# here I removed the binary file content
------WebKitFormBoundary5Z0hAYXQXBHPTLHs--

il est clair que vous pouvez gérer non seulement les données textuelles, mais aussi les téléchargements de fichiers aussi longtemps que vous écrivez un processeur de requête POST de manière appropriée. Bien que cela ne soit pas insignifiant, mais au moins c'est plausible et totalement faisable!

bien sûr, vous avez l'inconvénient évident que d'une certaine façon vous avez besoin de communiquer cette unique demander L'URL au client, ou au serveur qui lancer la requête. Mais techniquement, il y a plusieurs façons de le faire!

17
répondu Xin Yin 2014-08-14 03:59:03

Excitant de mise à jour: à partir de janvier 2017, il a été annoncé sur RStudio Conf que ceci sera intégré dans shiny dans une version future (commencez à regarder à la minute 15:00).

depuis mai 2017, cette fonctionnalité de L'API n'est toujours pas disponible, mais j'espère qu'elle viendra bientôt.

1
répondu Dean Attali 2017-05-27 02:15:22