Flask keep-alive
http 长连接
http/1.0默认不开启 connection:keep-alive
http/1.1默认开启
笔者想抓包测试一下http 1.1里面的长连接
一个简单的flask接口
# Flask==1.1.2
# Werkzeug==1.0.1
from flask import Flask, make_response
app = Flask(__name__)
@app.route('/hello', methods=['get'])
def hello():
res = make_response('hello world!')
return res
if __name__ == '__main__':
app.run(host='127.0.0.1', debug=True, port=5001)
postman发送请求,wireshark抓包(过滤条件: ip.addr==127.0.0.1 and tcp.port==5001)
下图首两行可以看到TCP协议,标志位SYN,握手报文。(深灰色)
倒数四行TCP协议,标志位FIN, 是挥手报文。(深灰色)
图里剩下的内容应用层http协议,这就是我们发送、响应的报文。(绿色)
即一次http请求、响应需要tcp完整握手与挥手,再发起一次http请求也是同样效果。

response header

响应的HTTP协议版本为1.0 ,默认不开启keep-alive

# 增加 Connection=keep-alive
res.headers['Connection'] = 'keep-alive'
重启flask服务,再次抓包。可以看到 TCP Keep-Alive网络包

response header, keep-alive

此时http请求完成后,并未关闭TCP,再次用postman请求会发现并未出现握手。

这个http长连接笔者等待了10分钟也还是keep-alive的状态...emmmm
当然,关闭postman或者后端服务后肯定断开了。
笔者重新安装了一个flask最新版测试
flask==2.1.3 再次测试
# Flask==2.1.3
# Werkzeug==2.1.2
from flask import Flask, make_response
app = Flask(__name__)
@app.route('/hello', methods=['get', 'post'])
def hello():
res = make_response('hello world')
return res
if '__main__' == __name__:
app.debug = True
app.run(host='0.0.0.0', port=5000)
同样用postman发送请求,发现握手与挥手的报文

response header中connection为 close

# 代码中加入Connection
res.headers['Connection'] = 'keep-alive'
postman测试,发现tcp还是挥手了。

response header中居然有两个connection!


笔者以为是没设置对,尝试了其他方式仍然不得行!后发现是WerkZeug里面就是设置的 close
#res.headers['Connection'] = 'keep-alive'
#res.headers.setdefault('Connection', 'keep-alive')
#res.headers.set('Connection', 'keep-alive')
WerkZeug包里面的serving文件

直接把源码改为Keep-Alive,果然就不会断开TCP了。
笔者查看了WerkZeug的更新记录,找到了日志说明。


由于WerkZeug使用的http服务是http.server这个python内置的http服务器,这里面的代码对http请求处理上存在问题导致的。
笔者终于找到原因了。(●ˇ∀ˇ●)
当然生产环境我们使用的WSGI HttpServer一般都会选择gunicorn或者uwsgi。不会使用WerkZeug。