通常一個新的 Notebook 在打開的時候,會自動連接當前服務器,創建一個 Session 和一個 Kernel 進程。該 Session 綁定在該 nb(notebook 簡稱,下同) 的路徑上,因此你要你的 server 不停,無論刷新 nb 還是打開該 nb 的一個新 tab,該 session 都是同一個 session,kernel 也是同一個 kernel。
以上是 Notebook 基本的前後端交互流程,本文關注的是當 nb 與 Kernel 不在同一個域下時,如何跨域連接的問題。即假設 nb 的地址是 a.com/xx.ipynb
,但我們想連接 b.com
的一個 kernel。
修改後端地址
首先是創建 Session 的調用,該調用發生在 session.js
第 122 行
utils.ajax(this.session_service_url, {
這裏需要修改爲你想要連接的域名,比如 'http://b.com' + this.session_service_url
。
session 與 kernel 創建完成後,nb 與 kernel 的交互會使用 websocket 通道。ws 地址是類似 ws://localhost
這樣的格式,定義在 notebook.html
模板中,在打開 nb 時由 server 進行渲染:
data-ws-url="{{ws_url | urlencode}}"
這兩處修改爲跨域地址後,你的 nb 就會自動向新服務器發請求,那麼自然你的新服務器需要在響應中添加跨域頭,這一點可以簡單通過修改配置文件實現:
c.NotebookApp.allow_origin = '*'
該配置項會在 /base/handlers.py
中被訪問:
[@property](https://my.oschina.net/property)
def allow_origin(self):
"""Normal Access-Control-Allow-Origin"""
return self.settings.get('allow_origin', '')
處理認證
當然 server 不是對連接來者不拒的。在認證上仍有兩處需要處理:
一是 xsrf token 認證,該認證可以在配置文件中關掉:
c.NotebookApp.disable_check_xsrf = True
二是用戶登錄認證。server 默認使用 token 的方式,該 token 會在渲染 nb 的時候寫入 page.html
裏:
data-jupyter-api-token="{{token | urlencode}}"
或者想直接繞過 auth 過程的話,修改 base/handlers.py
裏的 get_current_user
方法即可。
完成以上修改後,跨域連接 kernel 的功能就可以實現了。