当前位置:首页 > 开发 > 互联网 > 正文

Flask 出坑记

发表于: 2014-10-17   作者:薰衣草之子   来源:转载   浏览:
摘要: Flask 是个 Python Web 框架. 网站上文档例子都很详尽, 这里就不废话了, 只是来扯两个使用中需要注意的地方. 装饰器对被装饰函数的名字是敏感的     首先是应用程序装饰器, 如官网上的例子 ? 1 2 3 4 5 6 7 8 import flask app = flask.Flask

Flask 是个 Python Web 框架. 网站上文档例子都很详尽, 这里就不废话了, 只是来扯两个使用中需要注意的地方.
装饰器对被装饰函数的名字是敏感的

    首先是应用程序装饰器, 如官网上的例子

?
1
2
3
4
5
6
7
8
import flask
app = flask.Flask(__name__)
 
@app .route( '/' )
def hello():
     return 'Hello World'
 
if __name__ = = '__main__' : app.run(port = 7777 )


    这个装饰器挂在哪个函数上, 哪个函数就成为一个处理函数. 这个特性让那些看多了 django 或者 tornado 起手先一大堆类定义的人一下子全高潮了, 大呼简单函数拯救世界. 不过这东西有时候相当坑. 先来看一个熊孩子特性, 把上面代码改成这样

?
1
2
3
4
5
6
import flask
app = flask.Flask(__name__)
 
app.route( '/' )( lambda : 'Hello World' )
 
if __name__ = = '__main__' : app.run(port = 7777 )


    然后试着 curl 一下 http://localhost:7777, 没问题, 还是返回 'Hello World'. 好, 加一句

?
1
2
3
4
5
6
7
import flask
app = flask.Flask(__name__)
 
app.route( '/' )( lambda : 'Hello World' )
app.route( '/wtf' )( lambda : 'I bought a watch last year' )
 
if __name__ = = '__main__' : app.run(port = 7777 )


    再来一发

?
1
2
3
4
$ curl http: / / localhost: 7777 /
I bought a watch last year
$ curl http: / / localhost: 7777 / wtf
I bought a watch last year


    怎么都是「I bought a watch last year」?! 我去年买了个表!
    查了一通文档才发现 Flask 会索引被装饰函数的名字, 并根据这些名字来派发请求. 好了, 结论是不要在 Flask 里玩 lambda, 因为 Python 里面所有 lambda 名字都一个样

?
1
2
3
4
5
6
>>> x = lambda : None
>>> x.__name__
'<lambda>'
>>> y = lambda m, n: m + n
>>> y.__name__
'<lambda>'


    傲娇程序员的第一反应可能是「才不会到处用 lambda 只是偶尔写一个换换口味」. 且慢, 倒不是说 lambda 有问题, 而是下面这种用况会出事

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import flask
 
app = flask.Flask(__name__)
 
def handler_logger(f):
     def g( * args, * * kwargs):
         print 'before request'
         r = f( * args, * * kwargs)
         print 'after request'
         return r
     return g
 
@app .route( '/' )
@handler_logger
def root():
     return 'Hello World'
 
@app .route( '/wtf' )
@handler_logger
def wtf():
     return 'I bought a watch last year'
 
if __name__ = = '__main__' : app.run(port = 7777 )


    同样的结果, 访问两个 URL 看到的都是后一个函数的结果.
    刚才已经说了 Flask 对被包装函数的名字是敏感的, 所以解决上述问题的方法便是

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import flask
import functools
 
app = flask.Flask(__name__)
 
def handler_logger(f):
     @functools .wraps(f)
     def g( * args, * * kwargs):
         print 'before request'
         r = f( * args, * * kwargs)
         print 'after request'
         return r
     return g
 
@app .route( '/' )
@handler_logger
def root():
     return 'Hello World'
 
@app .route( '/wtf' )
@handler_logger
def wtf():
     return 'I bought a watch last year'
 
def main():
     app.run(port = 7777 )
 
if __name__ = = '__main__' : main()


获取 POST 请求体

    21 世纪的 Web 交互中服务器跟浏览器互相丢 JSON 已经成了司空见惯的事情. 服务器上要搞到 JSON 数据当然是直接访问 POST 请求体了, 如

?
1
2
3
4
5
6
7
8
9
10
11
12
13
import flask
import functools
 
app = flask.Flask(__name__)
 
@app .route( '/wtf' , methods = [ 'POST' ])
def wtf():
     return 'Received: ' + flask.request.data
 
def main():
     app.run(port = 7777 )
 
if __name__ = = '__main__' : main()


    按文档的说法, flask.request.data 包含请求数据字符串. 但其实这也是个坑, 默认情况下根本取不到请求数据

?
1
$ curl - d "[1,1,2,3,5,8]" http: / / localhost: 7777 / wtf


Received:
    熊孩子你把拿到的字符串给吃了吧? 实际上如果去看看那文档会看到并不如上面所说的那样, 而是
Contains the incoming request data as string in case it came with a mimetype Flask does not handle.
    后面这个状语从句真是着急, 那到底什么 mimetype 会使得 Flask does not handle 呢? 根本没说清楚啊. 扫一眼文档后面, 还有个东西可以用: flask.request.json, 但这货一般是 None, 只有当请求 mimetype 被设置为 application/json 的时候才有用, Flask 你真心是跟 mimetype 过不去啊. 也就是说得这样发请求

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
import json
import flask
import functools
 
app = flask.Flask(__name__)
 
@app .route( '/wtf' , methods = [ 'POST' ])
def wtf():
     return 'Received: ' + json.dumps(flask.request.json)
 
def main():
     app.run(port = 7777 )
 
if __name__ = = '__main__' : main()

 

?
1
2
3
4
$ curl - d "[1,1,2,3,5,8]" localhost: 7777 / wtf
Received: null
$ curl - d "[1,1,2,3,5,8]" - H "Content-Type:application/json" localhost: 7777 / wtf
Received: [ 1 , 1 , 2 , 3 , 5 , 8 ]


    问题是现在前端攻城狮都被浏览器兼容性折腾得满世界买表, 哪还有心情检查每个请求的 content-type 对不对. 况且这还只对 JSON 有效, 如果是山寨协议又怂了.
    好吧, 如果实在不行, 就挖到 WSGI 里面去好了, 比如这样

?
1
2
3
4
5
def request_data():
     d = flask.request.data
     if not d:
         return ' '.join(flask.request.environ[' wsgi. input '].readlines())
     return d


    这样 (在特定的 WSGI 环境中, 比如配合 gevent 使用时) 能获取请求数据 (这不还是坑么). 或者看看这个万能的方法. 好了, 请求字符串快到碗里来!

Flask 出坑记

  • 0

    开心

    开心

  • 0

    板砖

    板砖

  • 0

    感动

    感动

  • 0

    有用

    有用

  • 0

    疑问

    疑问

  • 0

    难过

    难过

  • 0

    无聊

    无聊

  • 0

    震惊

    震惊

编辑推荐
平时使用Vagrant+VirtualBox来配合使用,今天所在服务器异常关机后,再次启动vagrant up的时候,屏
最近用 Java 刷算法题的时候发现 Integer 有一个小坑,我把当时的代码简化如下: public class Lear
AEM是Adobe公司所出的商业内容管理系统,全称阿豆比体验管理系统(Adobe Experience Manager),其前
坑很多,跳之前做好准备。没有VPN的同学请浏览完本文后慎行。 你需要先安装最新版本的node.js(我最
今天,在搞一个很小的功能的时候,被this给小搞了一下!!!在此记录下来,以防止下次再犯错了。。
问题来源 因为经常有各种各样的大小项目要跑,全部放一个tomcat很慢,所以俺平时喜欢新建80-89这10
最近在做项目的涉及嵌入旧系统页面部分,前后一个多月时间,里面踩到各种坑,不写篇文章记录一下感
一.flask一个聊天或留言的: 目录结构: flask └── zdy ├── modle │ ├── __init__.py │
1.目录结构: root@bogon:~# tree flask/yw/ flask/yw/ ├── bootstrap.zip #下载的bootstrap,解
from flask import request 判断method方式 request.method 'POST', ‘GET’ 获取form内容 request.
版权所有 IT知识库 CopyRight © 2009-2015 IT知识库 IT610.com , All Rights Reserved. 京ICP备09083238号