Подтвердить что ты не робот

Принять HTTP-запрос в R-приложении

У меня есть блестящее приложение, которое я сделал, чтобы получить его данные с другого сервера, то есть другой сервер, когда открытое блестящее приложение отправляет запрос в блестящее приложение, чтобы открыть приложение и передать ему данные, которые он необходимо.

Чтобы имитировать это, я могу отправить следующее в блестящее приложение R, когда я открываю приложение в firefox:

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

Это простой запрос на получение запроса, который отправляет вызов: "Трансформаторные данные" с содержимым "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

но никто из них не работал.

SO главный вопрос: каким образом я могу кодировать для получения HTTP-запросов? Я хотел бы получать строки из HTTP GET-запросов и/или JSON файлов из запросов POST.

Просто, чтобы уточнить, я НЕ хочу отправлять сообщение или получать запросы от Р. Я хочу их получить. Я не могу использовать пакет httr или пакет httpRequest для получения

Большое спасибо!

4b9b3361

Ответ 1

Вы можете получать запросы GET с помощью session$clientData. В примере выполните следующие

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

@jdharrison ответ - один из способов, как вы можете обрабатывать запросы GET в Shiny. К сожалению, его выражение о том, что

shiny does not обрабатывает запросы POST, к сожалению.

не является, строго говоря, 100% точным.

Вы можете обрабатывать запросы POST в Shiny с помощью функции session$registerDataObj. Пример использования этой функции можно найти в этом примере. В основном, вызывая функцию registerDataObj, он возвращает URL-адрес запроса уникальный, к которому вы можете инициировать запросы GET или POST. Однако я не стал бы рассматривать приведенный выше пример очень полезным в контексте вашего вопроса, потому что:

  • В этом примере явно не используется AJAX. Скорее, этот пример использует registerDataObj для создания обработчика файла PNG и напрямую привязывает URL к свойству src тега <img>.
  • Он по-прежнему использует GET запрос не POST.

Но вы можете мультиплексировать эту удобную функцию, чтобы обрабатывать как GET, так и POST отлично. Рассмотрим следующий пример:

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. Хотя это может быть не тривиально, но, по крайней мере, это правдоподобно и полностью выполнимо!

Конечно, у вас есть очевидный недостаток, так как вам нужно сообщить этот уникальный URL-адрес клиенту клиенту или серверу, который инициирует запрос. Но технически есть много способов сделать это!

Ответ 3

Захватывающее обновление: по состоянию на январь 2017 года было объявлено в RStudio Conf, что это будет встроено в блестящее в будущей версии (начало смотреть в минуту 15:00).

По состоянию на май 2017 года эта функция API все еще не выпущена, но я надеюсь, что она скоро наступит.