1

语境

为了测试我正在编写的 R 包的 Web 功能,我尝试使用该httpuv包在本地提供文件,以便我可以使用页面的脱机副本运行测试。

问题

但是,curl似乎不想玩得很好httpuv- 特别是,当尝试使用curl(例如,with curl::curl()or curl::curl_fetch_memory())读取托管文件时,请求挂起,如果没有手动中断,最终会超时。

最小的例子

# Serve a small page
server <- httpuv::startServer("0.0.0.0", port = 9359, app = list(
  call = function(req) {
    list(
      status = 200L,
      headers = list("Content-Type" = "text/html"),
      body = "Some content..."
    )
  }
))

# Attempt to retrieve content (this hangs)
page <- curl::curl_fetch_memory(url = "http://127.0.0.1:9359")

httpuv::stopServer(server)

现在的进展

服务器启动后,curl -v 127.0.0.1:9359在终端上运行会按预期返回内容。此外,如果我打开一个新的 RStudio 实例并尝试curl::curl_fetch_memory()在那个新的 R 会话中使用(而旧的会话仍然打开),它会完美运行。

受此鼓舞,我已经玩callr了一段时间,想也许可以在某个后台进程中启动服务器,然后像往常一样继续。不幸的是,到目前为止,我在这种方法上还没有取得任何成功。

非常感谢任何见解或建议!

4

1 回答 1

0

Isn't it a great feeling when you can come back and answer a question you asked!

From the httpuv::startServer() documentation:

startServer binds the specified port and listens for connections on an thread running in the background. This background thread handles the I/O, and when it receives a HTTP request, it will schedule a call to the user-defined R functions in app to handle the request. This scheduling is done with later(). When the R call stack is empty – in other words, when an interactive R session is sitting idle at the command prompt – R will automatically run the scheduled calls. However, if the call stack is not empty – if R is evaluating other R code – then the callbacks will not execute until either the call stack is empty, or the run_now() function is called. This function tells R to execute any callbacks that have been scheduled by later(). The service() function is essentially a wrapper for run_now().

In other words, if we want to respond to requests as soon as they are received, we have to explicitly do so using httpuv::service(). Something like the following does the trick!

s <- callr::r_session$new()
on.exit(s$close())

s$call(function() {
  httpuv::startServer("0.0.0.0", port = 9359, app = list(
    call = function(req) {
      list(
        status = 200L,
        headers = list("Content-Type" = "text/html"),
        body = "Some content...")
      )
    }
  ))

  while (TRUE) httpuv::service()
})  

# Give the server a chance to start
Sys.sleep(3)
page <- curl_fetch_memory(url = "http://127.0.0.1:9359")
于 2020-05-28T16:35:40.610 回答