首页 >> 大全

flask 流式响应 RuntimeError: working outside

2023-12-22 大全 34 作者:考证青年

2019独角兽企业重金招聘工程师标准>>>

1、问题

最近要实现这样一个功能:某个 cgi 处理会很耗时,需要把处理的结果实时的反馈给前端,而不能等到后台全完成了再咔一下全扔前端,那样的用户体验谁都没法接受。

web 框架选的 flask,这个比较轻量级,看了下官方文档,恰好有个叫 from 的功能:

#-from-

可以满足需求,它以 为基础,流式的返回数据到前端。看了下官方的例子貌似很简单,一笔带过,我又搜了下 ,上面有个老外给了个更加详尽的例子: data with and Flask

文中的答案没有前后端的数据交互过程,那我就根据自己的需求加个 http 的交互过程了:

@app.route('/username', methods=['GET', 'POST'])
def index():req =requestprint reqprint "111------------"  + req.method + "\n"def ggg1(req):print req  # the req not my pass into the req....print "444------------" + req.method + "\n"if req.method == 'POST':if request.form['username']:urlList = request.form['username'].splitlines()i = 0for url in urlList():i += 1resultStr = urlprint i, resultStryield i, resultStrprint reqprint "222------------" + req.method + "\n"return Response(stream_template('index.html', data=ggg1(req)))

好吧,这么一加,噩梦就开始了。。。奇葩的问题出现了:

要么第 5 行和第 8 行不等,要么就是第 9 行报错:

if . == 'POST': # : of

继续在 上搜索,发现有人遇到了同样的问题,得到的建议是在调用前声明一个 上下文:

with app.test_request_context('/username', method='GET'):index()

折腾了老半天,还是依旧报错:: of

看起来似乎是在进入迭代器以前,原本的 的生命周期就已经结束了,因此就没办法再调用了。

那么要解决就有 2 种办法了:

_响应式流式布局_响应式布局和流式布局区别

(1)在进入 前将请求复制一份保存下来以供 调用。

(2)利用app. 创建的是一个全新的 ,将数据传给 使用。

以上这两种办法都曾试过,但是由于理解上的偏差,导致一直未能成功。后来经过 坚实同学的指点,才明白个中缘由,问题得以解决。

2、解决方案 (1)复制

将请求复制下来但不能直接 req = 这种形式,这只是给 取了个别名,它们是共享引用。正确的代码如下:

from flask.ctx import _request_ctx_stack
global new_request
@app.route('/')
@app.route('/demo', methods=['POST'])
def index():ctx = _request_ctx_stack.top.copy()new_request = ctx.requestdef generateFunc():if new_request.method == 'POST':if new_request.form['digitValue']:num = int(new_request.form['digitValue'])i = 0for n in xrange(num):i += 1print "%s:\t%s" % (i, n)yield i, nreturn Response(stream_template('index.html', data=generateFunc()))

PS: 其实像 这种以下划线开头的变量属于私有变量,外部是不应该调用的,不过坚实同学暂时也没有找到其他能正式调用到它的方法 ,就先这么用着吧。

(2)构造全新

上面的这种写法:with app.('/', ='GET'):

之所以不可以是因为 app. 创建的是一个全新的 ,它包含的 url, , , form 值都是要在创建时自定义的,它不会把原来的 里的数据带进来,需要自己传进去,类似这样:

with app.test_request_context('/demo', method='POST', data=request.form) as new_context:def generateFunc():

PS: 应该是做单元测试用的,用来模仿用户发起的 HTTP 请求。

它做的事,和你通过浏览器提交一个表单或访问某个网页是差不多的。

例如你传给它 url='xxx'、='post' 等等参数就是告诉它:向 xxx 发起一个 http 请求

(3)关于@

这是官方宣称在 1.0 中实现的一个新特性,#flask. 看说明应该可以更加优雅的解决上述问题,

但是试了下貌似不行,可能是组件间的兼容性问题。

_响应式布局和流式布局区别_响应式流式布局

(4)关于 with

New in 0.9.

Note that when you data, the is gone the the . Flask 0.9 you with a that can keep the the of the :

from flask import stream_with_context, request, Response@app.route('/stream')
def streamed_response():def generate():yield 'Hello 'yield request.args['name']yield '!'return Response(stream_with_context(generate()))

the () you would get a at that point.

REF:

#

3、结论

(1)flask. 和 兼容性不是很好,应该尽量不在 里调用 ,

把需要的值提前准备好,然后再传到 里。这里也有人遇到同样的问题:

#

用 没有效果应该也是上面这个原因。

(2)在文档语焉不详,同时 不到答案的时候,读源码或许是最后的选择,这也是一种能力吧。。。 - _ -

4、Refer:

附坚实同学的 与 sf 地址:

5、最后附上完整的测试源码:

# -*- coding: utf-8 -*-
import sysreload(sys)
sys.setdefaultencoding('utf-8')
from flask import Flask, request, Responseapp = Flask(__name__)def stream_template(template_name, **context):# http://flask.pocoo.org/docs/patterns/streaming/#streaming-from-templatesapp.update_template_context(context)t = app.jinja_env.get_template(template_name)rv = t.stream(context)# uncomment if you don't need immediate reaction##rv.enable_buffering(5)return rv@app.route('/')
@app.route('/demo', methods=['POST'])
def index():with app.test_request_context('/demo', method='POST', data=request.form) as new_context:def generateFunc():new_request = new_context.requestif new_request.method == 'POST':if new_request.form['digitValue']:num = int(new_request.form['digitValue'])i = 0for n in xrange(num):i += 1print "%s:\t%s" % (i, n)yield i, nreturn Response(stream_template('index.html', data=generateFunc()))if __name__ == "__main__":app.run(host='localhost', port=8888, debug=True)



Bootstrap 101 Template


Submit
nothing received yet
{% for i, resultStr in data: %} {% endfor %}

关于我们

最火推荐

小编推荐

联系我们


版权声明:本站内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 88@qq.com 举报,一经查实,本站将立刻删除。备案号:桂ICP备2021009421号
Powered By Z-BlogPHP.
复制成功
微信号:
我知道了