在R闪亮应用程序中接受HTTP请求

时间:2014-08-13 22:50:37

标签: r shiny shiny-server

我有一个闪亮的应用程序我需要从其他服务器获取其数据,即当闪亮的应用程序打开时其他服务器向闪亮的应用程序发送请求以打开应用程序并向其提供数据需要。

为了模拟这个,当我在firefox中打开应用程序时,我可以将以下内容发送到R闪亮的应用程序:

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

这是一个简单的get请求,它发送名为的sting: “变压器数据” 内容“data / TransformerDataSampleForShing.json”到闪亮的应用程序。

当我使用代码时,它可以正常工作:

#(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请求?我想从POST请求接收来自HTTP GET请求和/或JSON文件的字符串。

只是为了澄清我不想发送帖子或从R获取请求。我想收到它们。我不能使用httr包或httpRequest包来接收

非常感谢!

3 个答案:

答案 0 :(得分:17)

@ jdharrison的回答是如何处理Shiny中的GET请求的一种方式。 不幸的是,他或她的陈述

  

闪亮不幸地处理POST请求。

严格来说,

并非100%准确。

您可以借助函数POST 处理Shiny中的session$registerDataObj个请求。使用此函数can be found in this example的示例。基本上,通过调用registerDataObj功能,它会返回唯一请求网址,您可以向其发起GETPOST个请求。但是,我不认为上述示例在您的问题的上下文中非常有用,因为:

  1. 此示例中没有明确使用AJAX。相反,该示例利用registerDataObj创建PNG文件处理程序,并将URL直接绑定到src标记的<img>属性。
  2. 它仍在使用GET请求POST
  3. 但是,您可以复用这个方便的功能来完全处理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",你向Shiny服务器提交一个POST请求,根据我们的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请求处理器,您不仅可以处理文本数据,还可以处理文件上载。虽然这可能不是微不足道的,但至少它是合理的,完全可行的!

    当然,您有一个明显的缺点,就是您需要以某种方式将此唯一请求URL传递给客户端,或者发送请求的服务器。但从技术上讲,有很多方法可以做到这一点!

答案 1 :(得分:13)

您可以使用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

请参阅@Xin Yin答案,了解公开POST请求的方法。

答案 2 :(得分:1)

令人兴奋的更新:截至2017年1月,it was announced on RStudio Conf将在未来的版本中构建为闪亮的(在15:00开始观看)。

截至2017年5月,此API功能仍未发布,但我希望它很快就会推出。