Web 框架(七)
1. 什么是 wsgi
wsgi(Web Server Gateway Interface) (pep3333)
Python 服务器网关接口,它用于接受HTTP请求、解析HTTP请求、发送HTTP响应等底层操作。它的出现解决了 Python Web Server
乱象
它描述了web server(gunicorn /uwsgi)如何与 web 框架交互,web 框架如何处理请求。
def application(environ, start_reponse):
"""
application: WSGI app,一个可调用对象
environ:包含 WSGI 环境信息的字典,由 WSGI 服务器提供,常见的有 PATH_INFO、QUERY_STRING 等
start_reponse:生成 WSGI 响应的回调函数,接收两个参数,status 和 headers
返回值:返回响应体的迭代器
"""
status = '200 OK'
headers = [('Content-Type', 'text/html; charset=utf8')]
statrt_response(status, headers)
return [b'<h1>Hello World</h1>']
if __name__ == '__main__':
from wsgiref.simple_server import make_server
httpd = make_server('127.0.0.1', '8888', application)
httpd.server_forver()
2. 常见 web 框架 Django、flask 、tornado 对比
- Django:大而全:内置 orm 、admin、 组件,第三方插件多
- flask :微框架,插件机制,比较灵活,维护困难(插件:cookiecutter-flask :生成统一项目模板)
- Tornado:支持异步的微框架和异步网络库:第三方框架少
3. 什么是 MVC?
模型、视图、控制器:解耦数据
- M(Model)模型:负责业务对象和数据库的交互(ORM)
- V(View)视图:负责与用户的交互展示
- C(Control)控制器:接收请求参数调用模型和视图完成请求
ORM
ORM(Object Relational Mapping),对象关系映射,用于实现业务对象与数据表中的字段映射。比较出名的软件有:Sqlalchemy、Django ORM、Peewee
3、web 框架组成(淡化框架,加强基础)
4. web 安全问题
4.1 sql 注入
通过特殊的输入参数传入 web 应用,导致后端执行了恶意的 sql 语句
- 通常由于程序员未对输入进行过滤,直接动态拼接 sql 产生
- 可以使用开源工具
sqlmap
、sqlninja
检测
如何防范?
-
永远不要相信用户的输入
-
对输入参数做好检查(类型和范围),过滤和转义字符
-
不要拼接 sql,使用占位符或者 ORM 可以大大降低 sql 注入的风险
-
数据层:做好权限管理配置,不要明文存储存储信息
# sql 语句拼接(不推荐)
sql = "select * from users where name='"+ name +"' + "and password=md5('"+password+"')""
# SQL 语句注入,'---' 将后面的 SQL语句注释掉,从而到达不需要输入密码就能取出数据的目的
rose '--'
# 使用占位符
sql = "select * from users where name=%s and password=md5(%s)"
4.2 xss 跨站脚本攻击
恶意用户将代码植入到提供给其他用户使用的页面中,未经转义的恶意代码输出到其他用户浏览器被执行
-
用户浏览的页面被恶意植入 JS 语句,其他用户访问同一个页面时,JS文件被执行,从而到达攻击用户的目的。
-
主要分为两类:反射型(非持久型:放 url 中,发给用户,诱惑用户点击),存储型(持久型)
-
危害:盗取用户 cookie,获取敏感信息
如何防范?
过滤用户输入的特殊字符,如:<script>、<、>
等
bs4 = BeautifulSoup(article_content, 'html.parser')
# 过滤 script、link 标签
for tag in bs4.find_all():
if tag.name in ['script', 'link']:
tag.decompose() # 删除
4.3 csrf 跨站请求伪造
5. RESTful
RESTful(Representational State Transfer)表现层状态转化,是一种软件架构风格。
- 表现层状态转移,由 HTTP 协议主要设计者 Roy Fielding 提取
- 资源(Resources),表现层(Representation),状态转化(State Transfer)
- 是一种以资源为中心的 Web 软件架构风格,可以用 Ajax 和 RESTful Web 服务构建应用
名词解释
- 资源(Resources):使用 URI 指向一个实体
- 表现层(Representation):资源的表现形式,如:图片、文本、音频、HTML 文件等
- 状态转化(State Transfer):GET、POST、PUT、DELETE 等 HTTP 动词来操作资源,实现资源状态的改变
RESTful 准则
- 所有事务抽象为资源,资源对应唯一标识(identifier)
- 资源通过接口进行操作实现状态转移,操作本身无状态
- 对资源的操作不会改变资源的标识
RESTful API
RESTful 风格的 API 接口
- 通过 HTTP 动词(GET、POST、PUT、DELETE 获取/新建/更新/删除)资源,将 HTTP 动词语义和数据库的增删改查结合在一起
- 一般用 JSON 格式返回数据
- 一般 Web 框架都有相同的插件支持 RESTful API
前后端分离
后端负责提供数据接口,不再渲染模板,前端获取数据并呈现
- 前后端解耦,接口复用,(前端和客户端公用接口),减少开发量
- 各司其职,前后端同步开发,提升工作效率,定义好接口规范
- 方便调试 mock,测试和运维部署
5.1 如何设计 RESTful API
HTTP 方法 | URL | 动作 |
---|---|---|
GET | http://[hostname]/api/users | 检索用户列表 |
GET | http://[hostname]/api/users/[user_id] | 检索单个用户 |
POST | http://[hostname]/api/users | 创建新用户 |
PUT | http://[hostname]/api/users/[user_id] | 更新用户信息 |
DELETE | http://[hostname]/api/users/[user_id] | 删除用户 |
5.2 什么是 HTTPS
- HTTP 和 HTTPS 区别
- 什么是对称加密和非对称加密
- HTTPS 通讯过程是什么样的?可以使用 Wireshark 找包观察
6. 面试题
1、Django
请求生命周期?
-
wsgi
: 获取解析HTTP
请求,并转发给Web
框架 - 中间件:对请求进行校验或在请求对象中添加其他相关数据,如:
csrf、request、session
- 路由匹配:根据请求
URL
去匹配不同的视图函数 - 视图函数:在视图函数中进行业务逻辑的出来,涉及到:
orm、templates => 渲染
- 中间件:对响应的数据进行出来
-
wsgi
:将响应的内容发送给浏览器
2、Django
内置组件?
-
Admin
:对model
中对应的数据表进行增删改查提供的组件 -
model
:负责操作数据库 -
form
组件:生成HTML
片段,对数据有效性进行校验 -
ModelForm
:用于数据库操作,也可以用于用户请求的验证
3、列举 Django
中间件的 5 个方法,及应用场景?
-
process_request
:请求进来时,权限验证 -
process_view
:路由匹配之后,能够得到视图函数 -
process_exception
:异常时执行 -
process_template_response
:模板渲染时执行 -
process_response
:请求有响应时执行
以上方法的返回值可以是 None
,或者是一个HttpResponse
对象,如果是 None
,则继续按照django定义的规则向后继续执行,如果是 HttpResponse
对象,则直接将改对象返回给用户。
4、Django
的 request
对象是在什么时候创建的?
class WSGIHandler(base.BaseHandler):
request = self.request_class(environ)
请求到 WSGIHandler
类的时候,执行 __cell__
方法,将 environ
封装成 request
。
5、如何给 CBV
添加装饰器?
# 引入 method_decorator 模块
# 1. 直接给类加装饰器,所以请求方法(get、post 等)
@method_decorator(test, name='dispatch')
class LoginView(View):
pass
# 2. 单独给请求的函数添加装饰器
@method_decorator
def post(self, request, *args, **kwargs):pass
6、Django
如何实现 csrf
?
只对 post
请求进行 csrf
防御,第一次请求时,会在服务端随机产生一个 token
,把这个 token
放到 cookie
中,然后每次 post
请求都会携带这个 token
,这样就能避免 csrf
攻击了。
7、Django
中如何实现单元测试?
使用 untest
模块,coverage
生成测试覆盖度报告。
8、简述 MVC
和 MTV
?
-
MVC
(Model View Controller)
:模型-视图-控制器,是一种Web
架构模式。特点:把业务逻辑、模型数据、用户界面分离开来,让开发者将数据与表现解耦-
Model
:模型,数据库层面 -
View
:视图,系统中选择显示什么和如何显示的部分 -
Controller
:系统中根据用户输入并视需要访问模型,以决定使用哪个视图的那部分
-
-
MTV
(Model Templates View
):模型-模板-视图-
Model
:数据存取层,处理与数据所以事务,操作数据模型,如何读取数据等 -
Templates
:表现层,将模型中的数据通过页面的形式展示给用户 -
View
:业务逻辑层,包含存取模型以及调取恰当模板的相关逻辑,如:从模板中获取用户输入,写入模型中;从模型中读取数据放到模板中显示灯。
-
9、谈谈你对 restful
规范的认识?
restful
是一种软件架构风格,而非标准,它提供了一组设计原则和约束条件,主要用于客户端和服务端交互类的软件。
就像设计模式一样,并不一定要遵循这些原则,而是基于这个风格设计的软件可以更简洁、更有层次。
上面提到的规范:
1、restful 面向资源编程,url 接口尽量使用名词,不要使用动词
2、在 url 接口中推荐使用 HTTPS 协议,让网络接口更安全(https 在 http 基础上添加了一个 SSL 安全证书)
3、在 URL 中体现版本号(不同版本可以有不同接口)
https://v1.bootcss.com/mycss
4、url 中可以体现是否是 api 接口
https://www.bootcss.com/api/mycss
5、url 中可以添加条件去筛选匹配
https://www.bootcss.com/api/mycss?page=3
6、可以根据 http 不同的 method,进行不同的资源操作
GET、POST、DELETE、PUT、PATCH
7、响应式应该设置状态码
8、有返回值,而且格式为统一的 json 格式
9、返回错误信息
10、返回值中要提供帮助链接,即 api 最好做到 Hypermedia,若遇到要跳转的情况,携带跳转接口的 URL
10、接口幂等性是什么?
- 是系统的接口对外一种承诺(而不是实现)
- 承诺只要接口调用成功,外部多次调用对系统的影响都是一致的,不会对资源重复操作
11、为什么要使用 Django rest framework
框架?
可以自动生成符合 restful
风格的 api
- 在开发
rest api
视图中,虽然每个视图具体操作的数据不同,但增、删、改、查的流程基本一致,这部分代码可以简写 - 在序列化与反序列化时,虽然操作的数据不同,但执行过程却相似,这部分代码也可以简写
rest framework
可以帮助简化上述两部分的代码编写,大大提高 rest api
的开发速度
12、Django rest framework
框架中有哪些组件?
- 序列化组件
serializers
:对queryset
序列化以及对请求数据格式校验 - 路由组件
routers
:进行路由分发 - 视图组件
ModelViewSet
:帮助开发者提供了一些类,并在类中提供了多个方法 - 认证组件
- 权限组件
- 频率限制:请求频率限制
- 解析器
- 渲染器:定义数据如何渲染到页面上
- 分页:对获取到的数据进行分页处理
- 版本:版本控制用来在不同的客户端使用不同的行为
13、WSGI、uwsgi
和 uWSGI
的区别
-
WSGI
:Python
服务器网关接口,用于接收、解析HTTP
请求,并将响应等操作,解决了Python Web Server
乱象。- 实现
wsgi
的模块:wsgiref、werkzeug
,分别用于django、flask
,其本质是编写一个socket
服务端,用于接收用户请求
- 实现
-
uwsgi
:通信协议,是uWSGI
独占的协议,用于定义传输信息的类型 -
uWSGI
:Web
服务器,实现了WSGI、uwsgi、http 协议
, 把HTTP
协议转化成语言支持的网络协议供Python
使用
graph LR
A[www.xxx.com] -->|http协议| B(Nginx 服务器)
B(Nginx 服务器) --> |uwsgi协议| C(uWSGI 服务器)
B(Nginx 服务器) --> |uwsgi协议| D(uWSGI 服务器)
C(uWSGI 服务器) --> |WSGI 协议| E(Django/flask 框架)
D(uWSGI 服务器) --> |WSGI 协议| F(Django/flask 框架)
14、Django、flask
和 tornado
对比
-
Django
:大而功能全,内置很多组件,慢在于Django ORM
与数据库的交互上,所以是否选用Django
,取决于项目对数据库交互的要求以及各种优化,而对于 Django 的同步特性导致吞吐量小的问题,其实可以通过 Celery 等解决,倒不是一个根本问题。代表:Instagram
-
Flask
:微框架,插件机制,灵活,维护困难,代表:Pinterest
-
Tornado
:天生异步,性能强悍,需要自己实现的东西很多。代表:知乎
15、谈谈对 cookie、session、jwt
的理解?
cookie
由于 http
协议没有状态,而服务器端的业务必须要有状态的,cookie
的诞生是为了存储 web
中的状态信息,以方便服务器端使用(如判断用户是否是第一次访问网站)服务器向客户端发送 cookie
,浏览器将 cookie
保存,之后每次请求都会将 cookie
发送给服务器
session
由于 HTTP
协议是无状态的,这样就不能确定本次请求和上次请求是不是你发送的,如登录相关的操作就实现不了。
浏览器第一次访问服务器,服务器创建一个 session
,同时为该 session
生成一个唯一会话的 key
,即 sessionid
;将 sessionid
及对应的 session
分别作为 key
和 value
保存到缓存中,也可以持久化到数据库中。当浏览器请求时,再以 cookie
形式发送给客户端,这样下次浏览器再次访问时,会带着 cookie
中的 sessionid
,然后服务器根据 sessionid
找到对应的 session
进行匹配验证。
cookie
安全性不好,攻击者可以通过获取本地 cookies
进行欺骗或者利用 cookies
进行 csrf
攻击,使用 cookies
时,在多个域名下,会存在跨域问题。
session
存储在服务器端,当有大量用户时,会大幅度降低服务端的性能。
jwt
JSON WEB TOKEN
的简写。可以使用在 RESTFUL
接口定义, 也可以使用在普通的 web
,组成:
header
- 在
header
中声明一些信息 payload
首先用户发出登录请求,服务端根据用户的登录请求进行匹配,若匹配成功,将相关信息放入 payload
中,利用算法,加上服务端的密钥生成 token
,并将其返回给客户端,客户端下次请求时,将 token
一起交给服务端,一般是说我们可以将其放在 Authorization
首部中,这样就可以避免跨域问题。