在 R 会话中访问本地提供的文件

Access locally served files within an R session

上下文

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

问题

然而,curl 似乎并不想与 httpuv 一起玩得很好——具体来说,当尝试使用 curl 读取托管文件时(例如,使用 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)

当前进度

服务器启动后,运行在终端 returns 将 curl -v 127.0.0.1:9359 内容按预期显示。此外,如果我打开一个 RStudio 的新实例并尝试 curl::curl_fetch_memory() 在那个新的 R 会话中(而旧的仍然打开),它工作得很好。

受此鼓舞,我一直在研究 callr 一段时间,认为也许可以在某些后台进程中启动服务器,然后照常继续。不幸的是,到目前为止我还没有用这种方法取得任何成功。

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

当你能回来回答你提出的问题时,是不是感觉很棒!

来自 httpuv::startServer() 文档:

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

换句话说,如果我们想在收到请求后立即响应,我们必须使用 httpuv::service() 明确地这样做。像下面这样的东西就可以了!

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