一、状态码
当浏览者访问一个网页时,浏览者的浏览器会向网页所在服务器发出请求。当浏览器接收并显示网页前,此网页所在 的服务器会返回一个包含HTTP状态码的信息头(server header)用以响应浏览器的请求。
HTTP状态码的英文为HTTP Status Code。下面是常见的HTTP状态码:
200 - 请求成功
301 - 资源(网页等)被永久转移到其它URL
404 - 请求的资源(网页等)不存在
500 - 内部服务器错误
状态码的分类:
HTTP状态码由三个十进制数字组成,第一个十进制数字定义了状态码的类型,后两个数字没有分类的作用。HTTP状态码共分为5种类型:
1** - 信息,服务器收到请求,需要请求者继续执行操作
2** - 成功,操作被成功接收并处理
3** - 重定向,需要进一步的操作以完成请求
4** - 客户端错误,请求包含语法错误或无法完成请求
5** - 服务器错误,服务器在处理请求的过程中发生了错误
二、Cookie
Cookie,有时也用其复数形式Cookies,指某些网站为了辨别用户身份、进行session跟踪而储存在用户本地终端上的数据(通常经过加密)。实际上cookie是一个很小的文本文件,是浏览器储存在用户的机器上的。Cookie是纯文本,没有可执行代码。储存一些服务器需要的信息,每次请求站点,会发送相应的cookie,这些cookie可以用来辨别用户身份信息等作用。
特点:
•Cookie以键值对的格式进行信息的存储。
•Cookie基于域名安全,不同域名的Cookie是不能互相访问的,如访问jd.com时向浏览器中写了Cookie信息,使用同一浏览器访问baidu.com时,无法访问到jd.com写的Cookie信息。
•当浏览器请求某网站时,会将浏览器存储的跟网站相关的所有Cookie信息提交给网站服务器。
类型:
可以按照过期时间分为两类:会话cookie和持久cookie。会话cookie是一种临时cookie,用户退出浏览器,会话Cookie就会被删除了,持久cookie则会储存在硬盘里,保留时间更长,关闭浏览器,重启电脑,它依然存在,通常是持久性的cookie会维护某一个用户周期性访问服务器的配置文件或者登录信息。
Cookie的产生流程:
未携带cookie
服务器返回cookie到客户端
再次访问时,客户端会携带着服务器返回的cookie进行访问。
Cookie的所在域:
服务器1,服务器2,服务器3都与同一个第三方广告服务器签订了合作协议,当我们点击了服务器1里面的广告,进入到广告页面去看了商品a,cookie就会把这一举动记录下来,放在这个广告域的cookie中;当我们点击了服务器2里面的广告,进入到广告页面买了商品b,cookie也会把这一举动记录下来,放在这个广告域的cookie中;当我们访问服务器3里面的广告,广告端服务器检查你的cookie时就会发现你浏览过a,买过b,然后针对这些行为做一些什么举动大家懂得都懂
Cookie的配置:
views.py:
def cookie_(request):
response = HttpResponse()
response.set_cookie('user', 'admin')
response.set_cookie('area', 'China')
response.set_cookie('city', 'Beijing')
return response
urls.py:
path('cookie/', views.cookie_)
效果:
当我们没有访问 http://127.0.0.1:8000/cookie/ 时
当我们访问 http://127.0.0.1:8000/cookie/ 后
可以看见通过set_cookie方法我们成功设置了cookie,但是如果没有设置cookie的有效期,那么在浏览器关闭之后,cookie会自动删除,cookie的有效期可以通过max_age参数(单位为秒)进行设置
修改views.py中的cookie_视图
def cookie_(request):
response = HttpResponse()
response.set_cookie('user', 'admin', max_age=10)
response.set_cookie('area', 'China')
response.set_cookie('city', 'Beijing')
return response
重启django服务
user的有效期被成功设置为10秒,10秒钟后我们在访问主页,发现有效期为十秒的cookie就已经没了
当然,expires参数也可以设置cookie的有效时常,但当他俩同时存在且都以秒为单位时,系统使用的max_age参数的值;当expires参数不是以秒为单位时,系统使用的是expires参数的值
expires参数值的三种形式:
1. 以秒为单位,传入一个整数
2. 格林尼治时间,格式如:Thu, 20-May-2021, 21:12:12, GMT
3. datetime.datetime对象,格式如:datetime.datetime(2021,5,20,21,12,12)
secure参数:值为True时,只允许Https请求方式访问cookie;值为False时,没有限制
httponly参数:值为True时,会组织客户端的JavaScript访问cookie
domain参数:表示可允许访问cookie的域名
删除cookie(delete_cookie方法):
def cookie_(request):
response = HttpResponse()
response.set_cookie('user', 'admin', max_age=10, expires=20)
response.set_cookie('area', 'China')
response.set_cookie('city', 'Beijing')
response.delete_cookie('city')
return response
后台获取cookie:
views.py:
def get_cookie(request):
cookies_ = request.COOKIES
return HttpResponse(cookies_)
urls.py:
path('get_cookie/', views.get_cookie)
三、Session
又称“会话控制”,Session对象存储特定用户会话所需的属性及配置信息。这样,当用户在应用程序的Web页之间跳转时,存储在Session对象中的变量将不会丢失,而是在整个用户会话中一直存在下去。当用户请求来自应用程序的 Web页时,如果该用户还没有会话,则Web服务器将自动创建一个 Session对象。当会话过期或被放弃后,服务器将终止该会话。Session 对象最常见的一个用法就是存储用户的首选项。例如,如果用户指明不喜欢查看图形,就可以将该信息存储在Session对象中。
Session和Cookie的区别:Session存放于服务器中,Cookie存放于本地
因为session存放于服务器中,所以我们会用到数据库,具体操作在此处不用理解,后面会着重介绍
配置settings文件:
SESSION_ENGINE = 'django.contrib.sessions.backends.db'
db:配置的是关系型数据库(例如:Mysql)
SESSION_ENGINE = 'django.contrib.sessions.backends.cached_db'
cached_db:配置的是混合型的数据库(关系型数据库和非关系型数据库都行)
SESSION_ENGINE = 'django.contrib.sessions.backends.cache'
cache:配置的是非关系型数据库(例如:Redis)
SESSION_CACHE_ALIAS = "default" 如果是非关系型数据库,需要指定缓存的默认库
配置mysql数据库:
mysql的安装和配置:
推荐个软件:Navicat for MySQL
Navicat for MySQL 是管理和开发 MySQL 或 MariaDB 的理想解决方案。它是一套单一的应用程序,能同时连接 MySQL 和 MariaDB 数据库,并与 Amazon RDS、Amazon Aurora、Oracle Cloud、Microsoft Azure、阿里云、腾讯云和华为云等云数据库兼容。这套全面的前端工具为数据库管理、开发和维护提供了一款直观而强大的图形界面。
收费软件,有钱的请支持正版软件,没钱的可以参考链接https://www.cnblogs.com/yinfei/p/11427259.html进行安装
因为一个项目只用到一次数据库的配置,代码不用记,现查就好
Navicat for MySQL配置:
左上角文件 -> 新建连接 -> mysql -> 输入连接名(此处以django为例),和自己mysql数据库的密码 ->
右键点击连接 -> 新建数据库 -> 输入数据库名(此处以dj_test为例),选择字符集utf-8
settings.py:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'dj_test', # 数据库名称
'HOST': '127.0.0.1',
'PORT': 3306,
'USER': '用户名',
'PASSWORD': '用户密码'
}
}
SESSION_ENGINE = 'django.contrib.sessions.backends.db'
首先,我们需要下载一个第三方库:pymysql
然后在__init__.py文件中添加以下代码
from pymysql import install_as_MySQLdb
install_as_MySQLdb()
然后在项目文件夹的terminal终端中执行:python manage.py migrate
执行完在Navicat for MySQL相应的数据库中生成了很多张数据表
我们的session一般就是保存在生成的django_session表中
我们尝试添加一个session
view.py:
def set_session(request):
request.session['time'] = '2021-5-20'
request.session['country'] = 'Chine'
# 设置session的有效期,此处设置成10秒
request.session.set_expiry(10)
return HttpResponse('Session添加成功!')
urls.py:
path('session/', views.set_session)
我们重启django服务,访问 http://127.0.0.1:8000/session/ ,刷新Navicat for MySQL中的界面,就可以看到session被保存到了django_session表中,只不过是加了密的形式
可以看见我们的session成功保存在了mysql数据库中
配置Redis数据库:
首先需要安装一个第三方库:django_redis
在redis desktop manager中创建一个连接:点击最下面中间的connect to redis server -> 输入相关信息(django,120.0.0.1,6379)
然后在settings.py文件中添加以下代码
CACHES = {
"default": {
"BACKEND": "django_redis.cache.RedisCache",
"LOCATION": "redis://127.0.0.1:6379/0",
"OPTIONS": {
"CLIENT_CLASS": "django_redis.client.DefaultClient",
}
}
}
SESSION_ENGINE = 'django.contrib.sessions.backends.cache'
SESSION_CACHE_ALIAS = "default"
我们重启django服务,访问 http://127.0.0.1:8000/session/
可以看见我们成功把session信息保存到了redis数据库中,因为我们设置的有效期是10s,所以在10s后鼠标右键django,选择reload,发现session信息被删除了
session的删除:
request.session.flush()
request.session.clear()
clear:删除存储中的值,但是session还是存在的
flush:删除存储中的session,把整个session完全删除
四、类视图
类视图的定义:
使用类来定义的视图,称为类视图。
与函数视图的区分:
以函数的方式定义的视图称为函数视图,函数视图便于理解。
函数视图的缺点:遇到一个视图对应的路径提供了多种HTTP请求方式的支持时,便需要在一个函数中编写不同的业务逻辑,代码可读性与复用性都不佳。
使用类视图的好处:
1.代码可读性好。
2.类视图相对于函数视图有更高的复用性,如果其他地方需要用到某个类视图的特定逻辑,直接copy该类视图即可。
比如,当我们要处理不同的请求方式:
函数视图:
def deal(request):
if request.method == 'GET':
return HttpResponse('GET请求!')
elif request.method == 'POST':
return HttpResponse('POST请求!')
elif request.method == 'PUT':
return HttpResponse('PUT请求!')
elif request.method == 'CONNECT':
return HttpResponse('CONNECT请求!')
else:
return HttpResponse('其他请求!')
类视图:
class Deal(View):
def get(self, request):
return HttpResponse('GET请求!')
def post(self, request):
return HttpResponse('POST请求!')
def put(self, request):
return HttpResponse('PUT请求!')
def connect(self, request):
return HttpResponse('CONNECT请求!')
类视图的定义和使用:
首先需要在 views.py 文件中进行导包:
from django.views import View
定义的类视图必须继承于导入的 View 类
注意事项:
定义类视图中的方法时,get方法就是用来处理get请求的,post方法就是处理post请求的...每个方法用来处理对应的请求方式(方法名不能修改,必须是是请求方法)
类视图分发路由:path('路径/', views.类名.as_view())
views.py
class Deal(View):
def get(self, request):
response = HttpResponse()
response.write('<title>类视图</title>')
response.write('<b>类视图下处理get请求</b>')
return response
urls.py
path('class/', views.Deal.as_view())
效果:
类视图装饰器:
装饰器的作用:装饰器实质上就是一个函数,其可以让其他函数在不去改变任何代码的前提下增加额外的功能,装饰器的返回值是一个函数对象。
我们首先在 views.py 中定义一个装饰器,再定义一个类视图
def decorator(function, *args, **kwargs):
def wrapper(request, *args, **kwargs):
print('装饰器成功被使用!')
return function(request, *args, **kwargs)
return wrapper
class Deal(View):
def get(self, request):
response = HttpResponse()
response.write('<title>类视图</title>')
response.write('<b>类视图下处理get请求</b>')
return response
def post(self, request):
response = HttpResponse()
response.write('<title>类视图</title>')
response.write('<b>类视图下处理post请求</b>')
return response
那么如何使用装饰器呢?有两种方法:①. 装饰器(被装饰函数).(传入参数)
②. 语法糖:在要被装饰的函数上方加 @装饰器名
第①种方法在urls中分配路由:
path('class/', views.decorator(views.Deal.as_view()))
相当于先给 views.py 中的 decorator 函数分配路由,再把 views.py 中的 Deal 类视图作为参数传递
结果:无论发送get请求还是post请求,都会被装饰
注意:方法①添加装饰器会为类视图中所有的方法添加装饰器
第②种方法:
使用语法糖进行装饰首先需要导包
from django.utils.decorators import method_decorator
第一种语法糖格式:在类视图上方进行装饰
views.py
@method_decorator(decorator, name='dispatch')
class Deal(View):
def get(self, request):
response = HttpResponse()
response.write('<title>类视图</title>')
response.write('<b>类视图下处理get请求</b>')
return response
def post(self, request):
response = HttpResponse()
response.write('<title>类视图</title>')
response.write('<b>类视图下处理post请求</b>')
return response
使用我们前面导入的method_decorator,第一个参数传入我们自己写的装饰器,name参数值必须是请求方式,当它为dispatch时,会为类视图中所有的方法添加装饰器;当他为get时,会为类视图中的get方法添加装饰器;当他为post时,会为类视图中的post方法添加装饰器
第二种语法糖格式:在类视图的方法上进行装饰
class Deal(View):
@method_decorator(decorator)
def get(self, request):
response = HttpResponse()
response.write('<title>类视图</title>')
response.write('<b>类视图下处理get请求</b>')
return response
def post(self, request):
response = HttpResponse()
response.write('<title>类视图</title>')
response.write('<b>类视图下处理post请求</b>')
return response
在这种方法下就不用设置 name 参数的值,且只有添加了语法糖的方法在执行时会被装饰
五、中间件
Django中的中间件:django中的中间件是一个轻量级、底层的插件系统,可以介入Django的请求和响应处理过程,修改Django的输入或输出。中间件的设计为开发者提供了一种无侵入式的开发方式,增强了Django框架的健壮性。我们可以使用中间件,在Django处理视图的不同阶段对输入或输出进行干预
内置中间件介绍
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
1. django.middleware.security.SecurityMiddleware:做了一些安全处理的中间件。比如设置XSS防御的请求头,比如做了http协议转为https协议的工作等。
2. django.contrib.sessions.middleware.SessionMiddleware:session中间件。会给request添加一个处理好的session对象。
3. django.middleware.common.CommonMiddleware:通用中间件,会处理一些URL,比如baidu.com会自动的处理成www.baidu.com。比如/blog/111会处理成/blog/111/自动加上反斜杠。
4. django.middleware.csrf.CsrfViewMiddleware:保护中间件,在提交表单的时候会必须加入csrf_token,cookie中也会生成一个名叫csrftoken的值,也会在header中加入一个HTTP_X_CSRFTOKEN的值来放置CSRF攻击。SessionMiddleware必须出现在CsrfMiddleware之前。
5. django.contrib.auth.middleware.AuthenticationMiddleware:用户授权中间件。会给request添加一个user对象的中间件。该中间件必须在sessionmiddleware后面。
6. django.contrib.messages.middleware.MessageMiddleware:消息处理中间件。为了在多个模板中可以使用我们返回给模板的变量,并且简化操作。
7. django.middleware.clickjacking.XFrameOptionsMiddleware:防止通过浏览器页面跨Frame出现clickjacking(欺骗点击)攻击出现。
拓展:
一、 跨站点请求伪造攻击(Cross Site Request Forgery,简称CSRF):
利用浏览器cookie自动发送的特点。如果浏览器中的cookie保存了用户信息,该攻击利用了cookie共享机制获取了用户信息,因此可以正常通过系统的鉴权认证,实现非法操作。
下面以网上银行转账的例子来说明该攻击的流程。
1. 小明在网上银行(bank.com)转账,浏览器cookie记录了小明的用户信息。
2. 小明在未关闭浏览器的情况下,又新建了页面开始浏览帖子(sns.com)。
3. 小黑是个黑客,已经将伪造的请求链接包含在sns.com的页面中。
4. 小明点中了小黑提供的伪造链接,那么该请求将会使用cookie中的合法信息,通过了银行的认证系统,实现小黑的非法操作。
这样就实现了跨站点请求伪造攻击。
防御措施:
解决跨站点请求伪造攻击,一般有以下两种方法:Referer校验,Token校验
referer校验
在 HTTP 协议的请求头部含有一个字段叫 Referer,它记录了本次请求的来源地址。例如从A网站跳到B网站,那么在B网站的看到的referer值就是A网站的域名。
在上面的银行转账例子的攻击中,银行系统接收到的攻击请求的referer是sns.com。如果该系统增加了referer校逻辑,就可以判断本次请求是否来自本系统bank.com,如果不是则拒绝。因此如果银行系统看到请求的referer是sns.com,则可以拒绝访问。注意,第一次访问时,referer值会为空。所以referer校验的策略是,允许referer值是本服务域名和空值的请求通过。
Token校验
token校验的原理是用户第一次登陆成功之后,系统给用户颁发随机且唯一的token,用户下次请求的时候,将该token作为参数传到后台,后台通过过滤器或者拦截器校验该token是否合法。若合法,则放行,不合法则拒绝访问。前端可以把token值存在请求头或者请求参数中,都可以。
二、Clickjacking攻击
clickjacking保护是攻击者在自己的病毒网站上,写一个诱惑用户点击的按钮,然后使用iframe的方式将受攻击的网站(比如银行的网站)加载到自己的网站上去,并将其设置为透明的,用户就看不到了,然后再把受攻击的网站(比如银行网站)的转账按钮定位到病毒网站的按钮上,这样用户在点击病毒网站上的按钮的时候,实际上点击的是受攻击的网站(比如银行的网站)上的按钮,从而实现了在不知不觉中给攻击者转账的功能。
开发中间件:
定义方式:定义一个中间件工厂函数,然后返回一个可以被调用的中间件。中间件工厂函数需要接收一个可以调用的get_response对象。返回的中间件也是一个可以被调用的对象,并且像视图一样需要接受一个request对象参数,返回一个response对象。
step1:新建一个py文件用于定义中间件,如在子应用lq中。
step2:在该新建的py文件中定义中间件
step3:在settings文件中将自定义的中间件注册。格式:'子应用名.中间件py文件名.外函数名'即中间件的python路径
中间件的调用顺序:在请求视图被处理前,中间件由上至下依次执行,在请求视图被处理后,中间件由下至上依次执行。
理解:从外面回家,先进客厅,再进卧室;出去玩,先出卧室,再出客厅。