【问题标题】:Flask not processing other HTTP requests after Chrome browser accesses the web-siteChrome浏览器访问网站后Flask不处理其他HTTP请求
【发布时间】:2017-02-28 22:07:16
【问题描述】:

问题说明: 在我尝试从 Chrome 浏览器访问不存在的文件后,我在 Flask 上的 Web 服务器未处理 HTTP 请求。当 Chrome 关闭或访问确实存在的页面时,会立即处理积压的 HTTP 请求。

影响:网络服务器可用性较差。

问题:为什么会发生这种情况以及如何在不以线程模式运行 Flask 的情况下修复它?

我在网上找到的最接近的帖子是:github.com/pallets/flask/issues/2188 但找不到完全相同的问题和解决方案。期待您的想法 - 非常感谢您的帮助!

主要假设: Chrome 没有读取 404 响应的所有内容,Flask 正在等待读取所有内容

详情:

重现问题的步骤:

1) 运行最小的 Flask 应用程序 (http://flask.pocoo.org/docs/0.12/quickstart/):

from flask import Flask

app = Flask(__name__)

@app.route('/')
def hello_world():
    return 'Hello, World!'

app.run()    
  • 在 хттп://127.0.0.1:5000/ 上运行(按 CTRL+C 退出)

2) 验证您在浏览器或 curl 中收到“Hello world”响应:

curl -v localhost:5000/

3) 在 Chrome 中转到 localhost:5000/pagethatdoesnotexists 在浏览器中观察 Not Found 错误

4) 重复 curl -v localhost:5000/ 命令

观察连接已建立但未收到响应 例如:

curl -v 本地主机:5000/ * 尝试 ::1... * 连接失败 * 连接到 ::1 端口 5000 失败:连接被拒绝 * 尝试 127.0.0.1... * 连接到 localhost (127.0.0.1) 端口 5000 (#0)

GET / HTTP/1.1 主机:本地主机:5000 用户代理:curl/7.49.0 接受:/

5) 在 Chrome 中转到存在的页面或关闭 Chrome

观察对 curl 的即时响应:

  • HTTP 1.0,假设在正文之后关闭
  • 关闭连接 0 你好,世界!

可能需要多次尝试才能重现该问题。通常发生 10 次中的 8 次以上

其他信息:

1) 我可以使用 Safari 或 telnet 或 python 脚本代替 curl - 同样的问题

2) Safari 不会产生问题,Chrome 会产生问题

3) 尝试通过发送与 Chrome 完全相同的 http 请求来模仿 Chrome,但无法重现该问题。 Chrome 可能会做其他事情。

4) 当我在线程模式下运行 Flask(使用不同的线程处理每个请求)时,问题就消失了。

5) 版本:

Chrome 版本 56.0.2924.87(64 位)

Python 3.5.2 |Anaconda 4.1.1(64 位)| (默认,2016 年 7 月 2 日,17:53:06) [GCC 4.4.7 20120313 (Red Hat 4.4.7-1)] 在linux上

flask.版本 '0.11.1'

6) 问题也在 AWS Ubuntu 生产服务器机器上重现

7) 尝试在 404 http 响应中发送自定义标头,但没有成功

@app.errorhandler(404)
def page_not_found(e):
    # return render_template('404.html'), 404
    resp = make_response(render_template('404.html'), 404)
    # resp.headers['Connection'] = 'close'
    resp.headers['Cache-Control'] = 'no-cache, no-store'
    return resp

更新

我能够在没有 404 错误的情况下重现该问题,只需来自 Chrome 的正常 http 请求。 Flask 日志中没有观察到错误。

这里是video with the problem demonstration

另一件有趣的事 - 如果在 Chrome 浏览器中使用隐身窗口,则不会观察到问题。然而,在正常模式下清除缓存并不能解决问题。

【问题讨论】:

    标签: python google-chrome http flask


    【解决方案1】:

    启用线程。

    app.run(host='0.0.0.0', port=80, debug=True, threaded=True)
    

    TL;DR

    问题仍然有效。似乎Chrome在开启页面预取时并没有关闭连接,它会阻塞服务器的执行,从而阻止后续请求的处理。

    就我而言,问题更严重,因为基于 Android 的手机也使用此预取功能,结果相同,而且我无法更改每个客户端的设置。

    我的解决方案/解决方法是在底层 werkzeug 服务器 (https://werkzeug.palletsprojects.com/en/0.16.x/serving/#werkzeug.serving.run_simple) 中启用 threading 选项。当然,它在服务器端会占用更多资源,但它允许我们将行为不良的请求/客户端分离到单独的线程中,而不会阻塞其他请求。

    if __name__ == '__main__':
        logger.info('starting web server life cycle')
        app.run(host='0.0.0.0', port=80, debug=True, threaded=True)
    

    我还检查了请求处理是否正确完成,至少在 Flask 方面确实如此。所以问题一定出在 Chrome / 其他客户端或底层 werkzeug 服务器中。

    @app.before_request
    def filter_prefetch():
        logger.debug("before request")
        logger.debug(request.headers)
    # uncomment these to filter Chrome specific prefetch requests.
    #    if 'Purpose' in request.headers and request.headers.get('Purpose') == 'prefetch':
    #        logger.debug("prefetch requests are not allowed")
    #        return '', status.HTTP_403_FORBIDDEN
    
    
    @app.after_request
    def debug_after(response):
        logger.debug("after request")
        response.headers["Cache-Control"] = "no-cache, no-store, must-revalidate"
        response.headers["Pragma"] = "no-cache"
        response.headers["Expires"] = "0"
        response.headers['Cache-Control'] = 'public, max-age=0'
        response.headers['Connection'] = 'close'
        return response
    
    

    【讨论】:

      【解决方案2】:

      我遇到过两次同样的问题。

      同样的环境:纯Flask(无反向代理),最简单的应用。

      在您使用 Chrome/Chromium 打开 URL 后,Flask 将挂起并且不会响应其他客户端(curl、postman、firefox、python-request、..)。

      Chrome 的解决方法

      在 Chrome/Chromium 中禁用 URL 预测服务选项的实际名称在屏幕截图中

      真正的解决方案(Flask)

      即将推出(欢迎投稿!)。

      【讨论】:

      • 谢谢,@maxkoryukov!这是有道理的,并且解决方法有效。期待 Flask 中的真正解决方案。
      • 如果 Preload pages 在 chrome://settings/privacy 中打开,就会出现问题
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-03-31
      • 2019-08-26
      • 1970-01-01
      • 1970-01-01
      • 2018-01-11
      • 2019-11-24
      • 2011-07-04
      相关资源
      最近更新 更多