我正在參數化我的散景應用程序,通過讓我的Flask應用程序通過專用路徑傳遞請求的數據通過查詢字符串參數。我知道數據發送路徑起作用,因爲當我使用它作爲url到AjaxDataSource
時,我得到預期的數據繪圖。但是,當我嘗試使用requests.get
api進行等效操作時,我得到一個503響應代碼,這讓我覺得我違反了基本的東西,在我的有限webdev體驗中我無法完全理解。我做錯了什麼或違反了什麼?Flask中的代碼503與嵌入式散景服務器應用程序通過requests.get獲取jsonified數據()
我實際上需要更多的數據檢索靈活性,而AjaxDataSource
提供了其列表限制。我希望依靠requests
模塊來傳遞任意類實例,以及通過序列化和反序列化Json傳遞什麼。
這裏是我已經展示了從flask_embed.html得到的故障的小例子...
import requests
from flask import Flask, jsonify, render_template
import numpy as np
import pandas
from tornado.ioloop import IOLoop
from bokeh.application import Application
from bokeh.application.handlers import FunctionHandler
from bokeh.embed import autoload_server
from bokeh.layouts import column
from bokeh.models import AjaxDataSource,ColumnDataSource
from bokeh.plotting import figure
from bokeh.server.server import Server
import pdb
flask_app = Flask(__name__)
# Populate some model maintained by the flask application
modelDf = pandas.DataFrame()
nData = 100
modelDf[ 'c1_x' ] = range(nData)
modelDf[ 'c1_y' ] = [ x*x for x in range(nData) ]
modelDf[ 'c2_x' ] = range(nData)
modelDf[ 'c2_y' ] = [ 2*x for x in range(nData) ]
def modify_doc1(doc):
# get colum name from query string
args = doc.session_context.request.arguments
paramName = str(args['colName'][0].decode('utf-8'))
# get model data from Flask
url = "http://localhost:8080/sendModelData/%s" % paramName
source = AjaxDataSource(data = dict(x=[] , y=[]) ,
data_url = url ,
polling_interval = 5000 ,
mode = 'replace' ,
method = 'GET' )
# plot the model data
plot = figure()
plot.circle('x' , 'y' , source=source , size=2)
doc.add_root(column(plot))
def modify_doc2(doc):
# get column name from query string
args = doc.session_context.request.arguments
colName = str(args['colName'][0].decode('utf-8'))
# get model data from Flask
url = "http://localhost:8080/sendModelData/%s" % colName
pdb.set_trace()
res = requests.get(url , timeout=None , verify=False)
print("CODE %s" % res.status_code)
print("ENCODING %s" % res.encoding)
print("TEXT %s" % res.text)
data = res.json()
# plot the model data
plot = figure()
plot.circle('x' , 'y' , source=data , size=2)
doc.add_root(column(plot))
bokeh_app1 = Application(FunctionHandler(modify_doc1))
bokeh_app2 = Application(FunctionHandler(modify_doc2))
io_loop = IOLoop.current()
server = Server({'/bkapp1': bokeh_app1 , '/bkapp2' : bokeh_app2 }, io_loop=io_loop, allow_websocket_origin=["localhost:8080"])
server.start()
@flask_app.route('/', methods=['GET'])
def index():
res = "<table>"
res += "<tr><td><a href=\"http://localhost:8080/app1/c1\">APP1 C1</a></td></tr>"
res += "<tr><td><a href=\"http://localhost:8080/app1/c2\">APP1 C2</a></td></tr>"
res += "<tr><td><a href=\"http://localhost:8080/app2/c1\">APP2 C1</a></td></tr>"
res += "<tr><td><a href=\"http://localhost:8080/app2/c2\">APP2 C2</a></td></tr>"
res += "<tr><td><a href=\"http://localhost:8080/sendModelData/c1\">DATA C1</a></td></tr>"
res += "<tr><td><a href=\"http://localhost:8080/sendModelData/c2\">DATA C2</a></td></tr>"
res += "</table>"
return res
@flask_app.route('/app1/<colName>' , methods=['GET'])
def bkapp1_page(colName) :
script = autoload_server(model=None , url='http://localhost:5006/bkapp1')
script = appendQuery(script , "colName" , colName)
return render_template("embed.html", script=script)
@flask_app.route('/app2/<colName>' , methods=['GET'])
def bkapp2_page(colName) :
script = autoload_server(model=None , url='http://localhost:5006/bkapp2')
script = appendQuery(script , "colName" , colName)
return render_template("embed.html", script=script)
@flask_app.route('/sendModelData/<colName>' , methods=['GET'])
def sendModelData(colName) :
x = modelDf[ colName + "_x" ].tolist()
y = modelDf[ colName + "_y" ].tolist()
return jsonify(x=x , y=y)
def appendQuery(script , key , value) :
# Pass along the parameter as a query string to the script's src url: TODO this will formally be introduced in next release of Bokeh to avoid this hack
script_list = script.split("\n")
idxSrcAttr = 2
script_list[idxSrcAttr] = script_list[idxSrcAttr][:-1] + "&{}={}\"".format(key , value)
script = "\n".join(script_list)
return script
if __name__ == '__main__':
from tornado.httpserver import HTTPServer
from tornado.wsgi import WSGIContainer
from bokeh.util.browser import view
print('Opening Flask app with embedded Bokeh application on http://localhost:8080/')
# This uses Tornado to server the WSGI app that flask provides. Presumably the IOLoop
# could also be started in a thread, and Flask could server its own app directly
http_server = HTTPServer(WSGIContainer(flask_app))
http_server.listen(8080)
io_loop.add_callback(view, "http://localhost:8080/")
io_loop.start()
這裏的一些調試輸出...
C:\TestApp>python flask_embedJSONRoute.py
Opening Flask app with embedded Bokeh application on http://localhost:8080/
> C:\TestApp\flask_embedjsonroute.py(52)modify_doc2()
-> res = requests.get(url , timeout=None , verify=False)
(Pdb) n
> C:\TestApp\flask_embedjsonroute.py(53)modify_doc2()
-> print("CODE %s" % res.status_code)
(Pdb) n
CODE 503
> C:\TestApp\flask_embedjsonroute.py(54)modify_doc2()
-> print("ENCODING %s" % res.encoding)
(Pdb) n
ENCODING utf-8
> C:\TestApp\flask_embedjsonroute.py(55)modify_doc2()
-> print("TEXT %s" % res.text)
(Pdb) n
TEXT
> C:\TestApp\flask_embedjsonroute.py(56)modify_doc2()
-> data = res.json()
(Pdb)
File "C:\Anaconda3\lib\json\decoder.py", line 357, in raw_decode
raise JSONDecodeError("Expecting value", s, err.value) from None
json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)