web-dev-qa-db-ja.com

Rの光沢のあるアプリケーションでHTTPリクエストを受け入れる

別のサーバーからデータを取得する必要がある、作成した光沢のあるアプリがあります。つまり、光沢のあるアプリを開くと、他のサーバーが光沢のあるアプリにリクエストを送信して、アプリを開き、必要なデータをフィードします。

これをシミュレートするために、Firefoxでアプリを開いたときにRシャイニーアプリに以下を送信できます。

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

これは、「data /TransformerDataSampleForShing.json」という内容の「TransformerData」というスティングを光沢のあるアプリに送信する単純なgetリクエストです。

コードを使用すると、正常に機能します。

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

しかし、文字列「data/TransformerDataSampleForShiny.json」をハードコーディングするのではなく、まったく同じことをしたい場合は、上記のhttpリクエストからその文字列を受け取りたいと思います。どうすればいいですか?私はコードを試しました:

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

そして私も試しました:

....
jsonFile <- input$TransformerData

しかし、これらはどれも機能していません。

したがって、主な質問は、HTTPリクエストを受信するようにコーディングするにはどうすればよいですか? HTTP GETリクエストから文字列を受信したいのですが、POSTリクエストからJSONファイルを受信したいのですが。

明確にするために、私はRから投稿を送信したり、リクエストを取得したりしたくありません。それらを受信したいと思います。 httrパッケージまたはhttpRequestパッケージを受信に使用できません

本当にありがとう!

18
James Willcox

session$clientDataを使用してGETリクエストを受信できます。次の例を実行します

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)

に移動します

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

POSTリクエストを公開する方法については、@ XinYinの回答を参照してください。

13
jdharrison

@jdharrisonの答えは、ShinyでGETリクエストを処理する方法の1つです。残念ながら、彼または彼女の声明は

残念ながら、shinyはPOSTリクエストを処理しません。

厳密に言えば、100%正確ではありません。

関数session$registerDataObjを使用して、ShinyでPOSTリクエストを処理できます。この関数の使用例 この例にあります 。基本的に、registerDataObj関数を呼び出すと、uniqueリクエストURLが返され、そこからGETまたはPOSTリクエストを開始できます。ただし、上記の例は、次の理由から、質問のコンテキストではあまり役に立たないと思います。

  1. この例ではAJAXを明示的に使用していません。むしろ、この例ではregisterDataObjを利用してPNGファイルハンドラーを作成し、URLを<img>タグのsrcプロパティに直接バインドします。 。
  2. GETではなくPOSTリクエストをまだ使用しています。

ただし、この便利な関数を多重化して、GETPOSTの両方を完全にうまく処理することができます。次の例を考えてみましょう。

server.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))

})

ui.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>
')
    )
  )
))

ここで、次のテスト入力を入力するとします。

Some test input

次に、"Upload"を押して、POSTリクエストをShinyサーバーに送信します。これにより、Rコードに基づいて、ブラウザのPOSTリクエストがダンプされます。応答としてあなたにストリーミングします。

たとえば、次のようになります。

------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--

POSTリクエストプロセッサを適切に記述していれば、テキストデータだけでなく、ファイルのアップロードも処理できることは明らかです。これは簡単ではないかもしれませんが、少なくとももっともらしく、完全に実行可能です。

もちろん、このuniqueリクエストURLをクライアントまたはリクエストを開始するサーバーに通信する必要があるという明らかな欠点があります。しかし、技術的にはそれを行う方法はたくさんあります!

18
Xin Yin

エキサイティングなアップデート:2017年1月の時点で、 RStudio Confで発表されました これは将来のバージョンで光沢のあるものに組み込まれる予定です(15:00分に視聴を開始してください)。

2017年5月の時点で、このAPI機能はまだリリースされていませんが、すぐに提供されることを期待しています。

1
DeanAttali