如何从基于服务器的Jupyter Notebook连接到localhost中的服务?

时间:2019-08-20 22:30:36

标签: python jupyter-notebook connection localhost

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

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

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

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

有人对此有任何经验吗?也许一些示例代码?

1 个答案:

答案 0 :(得分:1)

全部-

好吧……我已经尝试了每种方法,并且一路接受了体面的教育。最重要的是,它有可能 从运行在远程服务器上的Jupyter Notebook(又名IPython)中调用基于本地主机的服务,并且还可能获得结果,以便在Python中使用(尽管有限制)。这很重要,因为它使生物学工作流能够调用Cytoscape桌面应用程序的基于REST的自动化接口。

我正在写这篇文章,以便继任者我可以看到这一点,从中获利,或者放弃。其他StackOverlow和独立文章的 tons 帮了我大忙,值得一提的是:

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()调用的参数),而该Java调用必须在本地浏览器中执行(而不是远程服务器)。基于浏览器的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语句……只是在IPython之前不要查找已设置的HTTP结果变量过渡到下一个单元格。请注意,这里的Timeout()之类的解决方法在这里无效,因为它似乎没有强制执行Execute()语句队列,因此您实际上 do 必须等到下一个单元格才能访问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 = var_value.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”,这是一个非常糟糕的消息。

请注意,某些网络文章假设可以通过将值存储为DIV语句的innerHTML,然后让HTML()或Javascript()函数读取innerHTML和把它返还。我还没有解决这个问题,但是如果它可以工作,那么Execute()可能就没有必要了。