繁体   English   中英

如何从基于服务器的 Jupyter Notebook 连接到本地主机中的服务?

[英]How to connect from server-based Jupyter Notebook to service in localhost?

注意:这与大多数 StackOverflow 用户的要求相反

我有一个在远程服务器上运行的 Jupyter 笔记本(通过浏览器)和一个在我的localhost上运行的测试服务。 我想远程服务器调用本地服务。

问题是在远程服务器上运行时连接到 localhost 连接到远程服务器的本地主机,而不是我自己的 PC(其中运行浏览器)。

我期待也许我必须使用 Javascript 才能做到这一点? 我猜这将是一个类似 AJAX 的调用,涉及回调。 我认为这使事情变得有些复杂。 有没有更简单的方法?

有人对这个有经验么?? 也许一些示例代码?

全部 -

好的......我已经尝试了各种方法,并且一路上得到了体面的教育。 底线,它可以调用从Jupyter笔记本基于本地主机服务(又名IPython中)在远程服务器上运行,它也有可能得到一个结果返回,因此它可以在Python中使用(虽然,有限制)。 这很重要,因为它使生物工作流程能够调用 Cytoscape 桌面应用程序的基于 REST 的自动化接口。

我写这篇文章是为了让继任者——我可以看到这一点并从中获利,或者放弃。 我得到了大量其他 StackOverlow 和独立文章的帮助......太多了,最突出的是:

ipython-notebook-javascript-python-communication

执行讨论

workaround-for-wrapping-a-js-function-in-python-in-jupyter-notebook

这个问题分为三个部分:

  • 执行 HTTP 操作(...假设 GET,但 POST、PUT 等也可以工作)
  • 获取 HTTP 状态和结果
  • 在 Python 中使用结果

有多重挑战:

  • 将 URL 和有效负载(用于 PUT/POST)传递给 HTTP 调用方
  • 当 HTTP 结果可用时(而不是之前)返回给调用者
  • 通过 Python 变量使 HTTP 结果可用

存在一个主要问题是因为 Python 是一种在基于浏览器 (IPython) 的环境中(部分)执行的传统同步语言。 通常,这不是问题,因为远程 Jupyter 服务器先执行一个完整的 Python 单元,然后再执行另一个单元。 出现问题是因为 HTTP 调用必须在 Javascript 中(即,在 %%js 或 %%javascript 单元格中或作为 IPython.display.HTML() 调用的参数),它在本地浏览器中执行(而不是远程服务器)。 基于浏览器的 Javascript 的基本原则是长时间(例如 HTTP)操作应该异步完成(例如,使用 Promise 的 Fetch()、使用 Yield() 的生成器或正常的 XMLHttpRequest 调用)以保持高度交互的浏览器性能。 对于等待答案的工作流,异步执行会通过回调地狱让一个糟糕的生物信息学 Python 程序员感到震惊。 此外,此类工作流预计会占用大量计算资源,并且不需要交互性……必须保留因果关系。

在 Javascript 中,解决方案的要点是使用同步XMLHttpRequest 调用。 这得到了一个同步的答案。 接下来,使用未记录的 IPython.notebook.kernel.execute() 将值存储到远程服务器上的 Python 变量中。 这是一个异步操作,必须最后完成。 (只有在Chrome浏览器中使用开发模式才能看到execute()的源码:F12->static/notebook/js/services/kernels/kernel.js,找到kernel.js/Kernel.prototype.execute) . 如果这是在单元格的末尾完成的,IPython 将在下一个单元格准备好或等待用户输入时暂停。 在这两种情况下,Python 内核似乎都在为 execute() 创建的语句队列提供服务。 如果这确实发生了,那么可以安全地预期包含 HTTP 结果的 Python 变量将准备好在后续单元格中读取。 可以肯定的是,如果 execute() 和 Python 变量提取在同一个单元格中执行,它不会准备好。

当您将“false”传递给 XMLHttpRequest.open() 函数时,将创建同步 XMLHttpRequest 调用。 一些浏览器可能会抱怨这一点,因为他们认为同步调用是邪恶的并且已被弃用。 最好使用不会抱怨的浏览器(例如 Chrome)。

奇怪:如果你调用 HTML() 来执行 Javascript,它应该是单元格中的最后一次调用; 否则,HTML() 调用将失败。 如果您将 HTML() 调用包装在 IPython.display.display() 调用中,您可以在它之后在同一个单元格中放置额外的 Python 语句……只是在 IPython 之前不要查找已设置的 HTTP 结果变量过渡到下一个单元格。 请注意,像超时()的解决方法是无效的位置,因为它似乎并没有强制执行()语句队列的处理,所以你确实有访问HTTP结果之前等待,直到下一个单元格。

这个 Javascript 单元创建了将完成工作的 Javascript 函数。 请注意 Cy* 命名约定,它不太可能与 IPython 浏览器代码发生冲突。

%%js

function CyHttpGet(url) {
  var xhr = new XMLHttpRequest()
  xhr.open('GET', url, false)
  xhr.send(null);
  if (xhr.status === 200) {
    return xhr.responseText;
  }
  else {
    return "bad news:" + xhr.status
  }
}

function CySetKernelVar(varValue) {
  varValue = varValue.replace(/'/g, "/'");  // Double any single quotes
        
  var command = "httpResult = '"+ varValue + "'";
        
  var kernel = IPython.notebook.kernel;
  kernel.execute(command);
}

这个 Python 单元进行实际的 HTTP 调用:

from IPython.display import HTML

javascript = """
<script type="text/Javascript">

// This is what actually executes the HTTP and sets the result as a Python variable
CySetKernelVar(CyHttpGet('http://localhost:1234'));

</script>
"""

HTML(javascript)

这个 Python 单元使用了 HTTP 结果(并且不能是前一个单元的一部分):

print(httpResult)

httpResult='xxx' # clear variable so we're not fooled if the Javascript code doesn't do what we thought it would

请注意,通过 Execute() 将值从 Javascript 传递到 Python 的能力确实取决于 Python 内核清除单元格之间的 Execute 队列。 如果这不是真的发生,我们希望不时在打印(httpResult)中看到“xxx” - 非常糟糕的消息。

请注意,一些网络帖子假设可以通过让 Javascript 将值存储为 DIV 语句的 innerHTML,然后让 HTML() 或 Javascript() 函数读取 innerHTML 并返回它来将值从 Javascript 传递到 Python。 我还没有让它工作,但如果它可以工作,那么 Execute() 可能不是必需的。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM