版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
请求响应循环其实大家对于HTTP协议应该是再熟悉不过了,它是超文本传输协议,定义了服务器和客户端之间信息交流的格式和传递方式。那么对于上面的问题,我们其实也可以大致的说出一个简易流程:按下Enter之后,浏览器会向URL地址发送一个HTTP请求在浏览器的背后,有一个后台程序,用于接收相关请求,并返回处理的结果浏览器接收结果,并渲染给终端用户查看事实上,每一个Web应用都包含这种处理模式,即“请求-响应循环(Request-ResponseCycle)”:客户端(浏览器等)发出请求,服务端处理请求并响应。我们再把上面的流程扩展到Flask服务器上,就是由浏览器生成的HTTP请求发送至Web服务器。Web服务器接收到请求后,经由WSGI协议把数据转换成Flask程序能够识别的数据后,传递给Flask程序。然后Flask程序再根据视图函数等处理相关请求,最后再返回响应给Web服务器。最终交由浏览器来渲染结果,比如加载CSS,执行JavaScript代码等等操作。我们可以看下下面的图片这里有两个概念我们要先明确下Web服务器:Web服务器是一类特殊的服务器,其作用是主要是接收HTTP请求并返回响应。我们常用的Web服务器有Nginx,tomcat等,相信大家都非常熟悉或多少听说些。WSGI:它确切来说应该是一种协议,或者接口规范。定义了web服务器和web应用(Flask等)之间的接口规范。只有Web服务器和Web应用都遵守了WSGI协议,那么他们才能正常通信。比如说在上一节我们使用app.run()启动测试服务器时,就是使用了Flask自带的Web服务器,当然这种服务器只能用来开发测试时使用,在生成环境,我们需要部署到Nginx等Web服务器上。在了解了Web程序的整体运行流程之后,我们再来深入的探究下Flask的工作原理。Flask上下文HTTP请求当Flask接收到客户端的请求后(后面的章节中我们都会直接省略Web服务器和WSGI的转换步骤),就会产生一些视图函数可以访问的对象,通过这些对象来处理请求,这就是请求对象--request。request对象包含了HTTP请求中的URL信息和相关的报文信息URL信息例如请求URL为:xxxx://xxx.xxxxxxxi.xxx/hello?name=xxxxx属性值path'/hello'full_path'/hello?name=xxxxx'host'xxx.xxxxxxxxi.top'host_url'xxxx://xxx.xxxxxxxx.top'base_url'xxxx://www.xxxxxx.top/hello'url'xxxx://xxx.xxxxxxxi.xxx/hello?name=xxxxx'报文信息属性或方法说明args查询字符串信息cookiescookies信息字典data字符串形式的请求数据form表单数据get_json()获取json类型的请求数据method请求的HTTP方法下面我们通过一个简单的例子来具体查看下@app.route('/test/')
def
test_view():
query
=
'Flask'
if
request.args:
query
=
request.args.get('name',
'Flask')
host
=
request.host
path
=
request.full_path
cookie
=
request.cookies
method
=
request.method
return
"""
<h1>
<p>query
string:
%s</p>
<p>host:
%s</p>
<p>path:
%s</p>
<p>cookies:
%s</p>
<p>method:
%s</p>
</h1>
"""
%
(query,
host,
path,
cookie,
method)当我们在浏览器输入:xxxx://xxx.0.0.1:5000/test/,可以得到当我们在浏览器输入:xxxx://xxx.0.0.1:5000/test/?name=luobo,可以得到在这里,request是一个全局的变量,我们可以在任何的视图函数中去使用它。当然,这仅仅局限在当前线程中,对于多线程服务器中,不同线程服务器的请求对象是不同的。两种上下文在Flask中,有两种上下文:程序上下文和请求上下文。主要包括下面四种变量名上下文类型说明request请求上下文请求对象,封装了HTTP请求中的内容session请求上下文请求上下文用户会话,存储请求之间需要保留的值g程序上下文处理请求时的临时存储对象,仅在当前请求有效current_app程序上下文当前的程序实例对于request,我们已经了解了,下面再来看看session。sessionsession最常用的就是确认用户状态了,比如检查用户是否登陆等。下面我们就简单实现一个基于浏览器的用户认证功能,来理解下session的强大功效。普通的认证系统,用户在页面表单中输入用户名和密码后,后台程序进行确认,如果认证通过,则返回响应,并在浏览器的Cookie中设入标记,例如“loginID:User1”。但是因为浏览器Cookie是很容易被修改的,所以如果使用名称存储这些信息就会非常不安全,此时就需要session登场了。在Flask中session通过密钥对数据进行签名从而加密数据,所以我们需要先设置一个密钥。app.secret_key
=
'Very
Hard
Secret'当然,更加安全的做法是把该密钥写到部署服务器的环境变量中,对于这种写法,我们在后面部署程序时再详细讲解。
接下来我们做模拟用户认证的情况,写两个视图函数,分别模拟登陆和登出场景。@app.route('/login/')
def
login():
session['loginID']
=
'admin'
return
redirect(url_for('welcome'))@app.route('/logout/')
def
logout():
if
'loginID'
in
session:
session.pop('loginID')
return
redirect(url_for('welcome'))再修改welcome视图函数,用于展示是否登陆@app.route('/user/',
defaults={'name':
'陌生人'})
@app.route('/user/<name>')
def
welcome(name):
res
=
'<h1>Hello,
%s!</h1>'
%
name
if
'loginID'
in
session:
res
+=
'Authenticated'
else:
res
+=
'UnAuthenticated'
return
res这里我们使用了redirect函数,是一个重定向方法。只需要传入目标的URL地址,就可以在视图函数处理结束后跳转至目标的页面。当我在浏览器输入:xxxx://xxx.0.0.1:5000/login/的时候,就会在浏览器中插入一个加密的cookie并跳转至welcome页面可以看到,插入的cookie是加密的,这样就加大了攻击者的攻击难度,从而在一定程度上保护了我们系统的安全。g和current_app其实你应该会有个疑惑,我们已经有了一个app程序实例了,为什么还需要定义一个current_app变量呢?在不同的视图函数中,request对象都表示和视图函数对应的请求,也就是当前请求(currentrequest)。而程序会有多个程序实例的情况,为了能获取对应的程序实例,而不是固定的某一个程序实例,我们就需要使用current_app变量。当然对于多个程序实例的情况,我们留待后面的章节详细介绍。g存储在程序上下文中,而程序上下文会随着每一个请求的进入而激活,随着每一个请求的处理完毕而销毁,所以每次请求都会重设这个值。比如说如果对于某个请求,我们几个视图函数都需要用到一个前端传递过来的变量,那么就可以把它保存到g变量当中
=
request.args.get('name')这样,其他的视图函数就可以在同一个请求中直接使用来访问,而不用每次都调用request了。
对于current_app和g的更多使用方式,在后面的学习中我们会慢慢接触的更多。请求钩子在处理请求之前或之后执行的代码,就称为请求钩子。比如在请求之前,我们需要初始化数据库,创建admin用户等等,就需要在请求之前调用请求钩子来做这件事情。在Flask中提供了四种请求钩子,以装饰器的形式注册到函数,使得我们可以方便的应用该功能.钩子名称作用before_first_request在处理第一个请求之前运行before_request在每次请求之前运行after_request如果没有未处理的异常抛出,则在每次请求之后运行teardown_request即使有未处理的异常抛出,也在每次请求之后运行在请求钩子函数和视图函数之间共享数据一般使用上下文全局变量g,比如上面的例子我们就可以写成from
flask
import
g
@app.before_request
def
get_name():
=
request.args.get('name')重定向回上一个页面功能实现重定向回上一个页面,这应该是一个非常常见的应用场景,那么该如何通过Flask来实现呢。首先我们修改下login视图函数,在请求参数中查找next参数,如果存在则重定向到next参数对应的地址,否则重定向到hello视图函数对应的地址@app.route('/login/')
def
login():
session['loginID']
=
'admin'
return
redirect(request.args.get('next')
or
url_for('hello'))这里所谓的next参数,其实只是一种约定俗成的命名方式再修改needpage1视图函数,如果用户未登陆则展示登陆链接,并保存next参数@app.route('/needlogin1/')
def
needLogin1():
if
'loginID'
in
session:
return
'<h1>Hello,
needLogin1!</h1>'
else:
return
"""
<h1>Login</h1><a
href="%s">Go
To
Login</a>
"""
%
url_for('login',
next=request.url)这样,当用户处于未登录状态时,就可以点击GoToLogin链接进行登陆,登陆成功之后会自动跳转回当前页面了。安全处理现在我们虽然完成了功能,但是却还遗留了相关的安全问题。因为我们的next参数是以查询字符串的方式写在URL里的,所以如果有人拦截了我们的请求,就可以随便修改next的指向,此时我们就需要验证next变量是否属于我们的应用,否则很容易被指向外部链接,从而造成安全隐患。我们先创建一个检查URL正确性的函数from
urllib.parse
import
urlparse
def
check_next(target):
ref_url
=
urlparse(request.host_url)
test_url
=
urlparse(target)
return
ref_loc
==
test_loc该函数接收目标地址为参数,并比较本应用的host_url和目标地址的host_url是否相同
改写login视图函数@app.route('/login/')
def
login():
session['loginID']
=
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2024年广东省普通高等学校招收中等职业学校毕业生统一模拟考试语文题真题(原卷版)
- 卡斯钦-贝克病的健康宣教
- 干呕的健康宣教
- 足趾痛的健康宣教
- 毛孔堵塞的临床护理
- 子宫炎的健康宣教
- 孕期积食的健康宣教
- 《第一章》课件-1.1人工智能的诞生
- 皮肤脓肿的临床护理
- 《Java程序设计及移动APP开发》课件-第10章
- 技能人才评价新职业考评员培训在线考试四川省
- 铁道基础知识考试题库(参考500题)
- 课堂观察量表
- (现行版)江苏省建筑与装饰工程计价定额说明及计算规则
- 音乐鉴赏智慧树知到答案章节测试2023年山东科技大学
- 浅谈企业创新经营模式之供应链融资在纸张贸易中的运用
- 《学前儿童语言教育与活动实施》第十章 图画书在学前儿童语言教育中的运用
- 双管同沟敷设管道施工工法
- 小学语文整本书阅读推进课研究-以《中国神话故事》为例
- JJG 8-1991水准标尺
- 2022企业经营管理者如何应对信任危机事件
评论
0/150
提交评论