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

3

注意:这与大多数StackOverflow用户提出的问题相反

我在远程服务器上运行Jupyter笔记本(通过浏览器),同时在本地主机上运行测试服务。 我想从远程服务器调用本地服务。

问题在于,当在远程服务器上运行时,连接到localhost会连接到远程服务器的localhost,而不是我的电脑(其中运行着浏览器)。

我希望可能需要使用JavaScript来解决这个问题?? 我猜这将是类似AJAX的调用,涉及回调。 我认为这会使事情变得更加复杂。 有没有更简单的方法?

有人有经验吗?? 可以提供一些示例代码吗?


我认为这是不可能的。你可能需要在本地电脑上运行Jupyter或将该服务复制到远程服务器上。 - vb_rises
1个回答

阿里云服务器只需要99元/年,新老用户同享,点击查看详情
2

全部 --

好的...我已经尝试了各种方法,并且在这个过程中得到了不错的教育。归根结底,从远程服务器上运行的Jupyter Notebook(也称为IPython)可以调用基于本地主机的服务,并且可能还可以获取结果以便在Python中使用(虽然有限制)。这很重要,因为它使生物工作流能够调用Cytoscape桌面应用程序的基于REST的自动化接口。

我正在编写这篇文章,以便后继者可以看到并受益,或者放弃。我得到了其他StackOverlow和独立文章的大量帮助...太多了,无法一一列举,最突出的是:

ipython-notebook-javascript-python-communication

Execute Discussion

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)操作应异步完成(例如使用Promises的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变量获取,则很可能不会准备好。

当你向XMLHttpRequest.open()函数传递“false”时,会创建一个同步的XMLHttpRequest调用。一些浏览器可能会抱怨,因为它们认为同步调用是有问题的并已被弃用。最好使用一个不抱怨的浏览器(例如,Chrome)。

奇怪的事情:如果你调用HTML()来执行Javascript,它应该是单元格中的最后一个调用;否则,HTML()调用将失败。如果你将HTML()调用包装在IPython.display.display()调用中,在同一单元格中可以放置其他Python语句……只是不要指望HTTP结果变量被设置,直到IPython转换到下一个单元格。请注意,像Timeout()这样的解决方法在这里是无效的,因为它似乎不能强制处理Execute()语句队列,所以您真正需要等到下一个单元格才能访问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队列的能力。如果这并没有真正发生,我们会时不时地从print(httpResult)中看到"xxx",这是非常糟糕的消息。 请注意,一些网帖假定通过将值存储为DIV语句的innerHTML来从Javascript传递值到Python,并且然后使用HTML()或Javascript()函数读取innerHTML并返回它。我还没有让这个方法起作用,但如果可以,Execute()可能就不必要了。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,