Flask狼书笔记 | 01_初识Flask,02_Flask与HTTP(1):https://developer.aliyun.com/article/1407208
自定义Flask命令:
- Click官方文档(自定义命令):http://click.pocoo.org/6/
@app.cli.command() def hello(): click.echo('Hello, Human!')
> flask hello Hello, Human!
视图函数之名:可以溯源至MVC架构,即”模型 - 视图 - 控制器”。但flask并不是MVC架构的框架,因为没有内置数据模型的功能(需使用扩展),视图函数成为控制器函数才更加合适。(p28)
2 Flask与HTTP
request对象常用的属性和方法:(p43)
Response类常用属性和方法:(p48)
查看路由列表:这个列表由app.url_map
解析得到。其中static为Flask添加的特殊路由,用来访问静态文件。
> flask routes
Flask内置的URL变量转换器:(p37)
URL规则中的转换器:<转换器:变量名>
,
@app.route('goback/<int:year>') def go_back(year): return '<p>Welcome to %d!</p>' % (2018 - year)
请求钩子:也称回调函数,可以用来注册在请求处理的不同阶段执行的处理函数,如预处理、后处理,它们使用装饰器 实现。(p58)
响应:大多数情况下,我们只负责返回响应的主体内容(而不负责首部及各种字段)。Flask会调用make_response()方法将视图函数返回值转换为响应对象。当然,响应也可以包含响应主体、状态码、首部字段 三个部分内容。可使用redirect()
方法重定向。
@app.route('/') def hello_flask(): return '', 302, {'Location':'https://www.baidu.com'}
注:状态码不可儿戏,如将上面的302
改为202
,则重定向会失效。
错误响应:在视图函数中使用abort(<状态码>)
,例如:
@app.route('/404') def not_found(): abort(404)
响应格式:在 HTTP 响应中,数据可以通过多种格式传输,默认为 HTML。可以设置不同的 MIME 类型来标识不同的数据格式,MIME 类型在 Content-Type 字段中定义。
# method 1 - 修改响应对象的属性 # @plain 纯文本 from flask import make_response ... response = make_response("hello") response.mimetype = 'text/plain' # method 2 - 设置首部字段 response.headers['Content-Type'] = 'text/html; charset=utf-8'
- XML:
application/xml
,一般作为 AJAX 请求的响应格式,或是 Web API 的响应格式。 - JSON:
application/json
,指 JavaScript Object Notation(JavaScript对象表示法),更轻量、易解析。
- json模块的dumps()方法,可以将python中的字典、列表、元组数据序列化为json字符串。
# 1 - python标准库的json模块 response = make_response(json.dumps(data)) response.mimetype = 'application/json' return response # 2 - 使用flask包装的jsonify()函数 return jsonify(data)
Cookie:HTTP 是无状态协议。Cookie是保存在浏览器上的小型文本数据,保存一定时间,在下一次向同一个服务器发送请求时附带这些数据。但明文存储存在安全隐患。
使用set_cookie()方法设置(参数见p68),从cookies属性获取。
Session:在Flask中,session对象用来存储加密的cookie。
- 设置程序密钥:通过
Flask.secret_key
属性;或环境变量SECRET_KEY
(可保存在.env
文件),在脚本中通过getenv()
方法获取。
import os app.secret_key = os.getenv('SECRET_KEY', 'secret string')
疑问:写进了环境变量还需再脚本中手动获取?那我随便用个环境变量名称是不是也可以?
疑问:看不懂:使用session对象存储的Cookie,用户可以看到其加密后的值,但无法修改它。因为session中的内容使用密钥进行签名,一旦数据被修改,签名的值也会变化。这样再读取时,就会验证失败,对应的session值也会失效。 (p51)
- session cookie的保存时间:
上下文:Flask中有两种上下文:程序上下文 和请求上下文 。
两种上下文在视图函数中都会自动激活,这也意味折一些依赖于上下文的函数只能在视图函数中使用,如url_for()
、jsonify()
等。
也可手动激活程序上下文:
>>> from app import app >>> from flask import current_app # 方法1 >>> with app.app_context(): ... current_app.name # 方法2 >>> app_ctx = app.app_context() >>> app_ctx.push() >>> current_app.name >>> app_ctx.pop() # 激活请求上下文类似 >>> from app import app >>> from flask import request >>> with app.test_request_context('/hello'): ...
疑惑:g、request等对象如何区分不同的客户端?
上下文钩子:使用它注册的回调函数会在程序上下文被销毁时调用。
@app.teardown_appcontext def teardown_db(exception): ... db.close()
2.1 重定向回上一个页面
利用referrer或URL的查询参数。(p59)
referrer:即访问来源。当用户在某个站点单击链接,浏览器向新链接所在的服务器发起请求,请求的数据中包含的HTTP_REFERER字段记录了用户所在的原站点URL。
疑惑:书中判断url是否安全的代码(如下)使我困惑了许久:既然test_url中也与request.host_url做了拼接,那最后的netloc不是必然相同吗?
后来我查找了urljoin(base, url)函数的处理机制:
如果url是一个相对URL,那么urljoin会从url中获取路径部分,并于base中获取的部分合并;
如果url是一个绝对URL,则urljoin会直接返回url。
那么在什么情况下,is_safe_url函数的返回值才为False呢?
首先,target是一个绝对URL。
同时,该绝对URL的协议或主机不是本机。
综上,还是感觉该函数的逻辑写得有些隐晦了,不便于理解(肯定不能是我太笨)。
def is_safe_url(target): ref_url = urlparse(request.host_url) test_url = urlparse(urljoin(request.host_url, target)) return test_url.scheme in ('http', 'https') and \ ref_url.netloc == test_url.netloc
2.2 使用AJAX技术发送异步请求
jQuery中和AJAX相关的方法和具体用法:http://api.jquery.com/category/ajax/
前言
在传统的Web应用中,程序的操作都是基于请求响应循环来实现的。每当页面状态需要变动,或是需要更新数据时,都伴随折一个发向服务器的请求。当服务器响应时,整个页面会重载,并渲染新页面。
频繁更新页面会牺牲性能,且影响用户体验。
AJAX是指异步Javascript和XML(Asynchronous JavaScript And XML),是一系列技术的组合体,如XMLHttpRequest、JavaScript、DOM。它让Web程序更像是程序,而非一堆用链接和按钮链接起来的网页资源。
可以使用 jQuery 实现AJAX操作:函数ajax()可以发送AJAX请求。
2.3 HTTP服务器推送
推送技术对比:https://stackoverflow.com/a/12855533/5511489
- 传统轮询
- 长轮询
- SSE(Server-Sent Events)
- Websocket
2.4 Web安全防范
OWASP(Open Web Application Security Project,开放式Web程序安全项目):https://www.owasp.org 。(p66)
常见攻击方式:
注入攻击
XSS攻击(Cross-Site Scripting,跨站脚本):将代码注入被攻击者的网站
CSRF攻击:(Cross Site Request Forgery,跨站请求伪造):伪造用户的登陆状态。
提示:虽然在实际开发中,通过在”删除“按钮中加入链接来删除资源非常方便,但安全问题应该作为编写代码时的第一考量,应该将这些按钮内嵌在使用了POST方法的form元素中。攻击者就无法通过GET请求来修改用户的数据。
疑惑:未理解csrf攻击的防御原理。