第四章 探究 FBV 视图
视图是 Django 的 MTV 的架构模式的 V 部分,主要负责处理用户请求和生成相应的响应内容,然后在页面或其他类型文档中显示。使用视图函数处理 HTTP 的请求,即在视图函数中定义函数,这种方法称为 FBV 。
4.1 设置响应方式
网站的运行原理是遵从 HTTP 协议,分为 HTTP 请求和 HTTP 响应。 HTTP 响应方式也称为 HTTP 状态码,分为 5 中状态:消息、成功、重定向、请求错误和服务器错误。若以使用频率划分,则 HTTP 状态码可分为:成功、重定向和异常响应(请求错误和服务器错误)。
4.1.1 返回响应内容
视图函数是通过 return 方式返回响应内容,然后生成相应的网页内容呈现在浏览器上。不同的响应方式代表不同的 HTTP 状态码,其核心作用是 Web Server 服务器用来告诉浏览器当前网页请求发生了什么事,或者当前 Web服务器的响应状态。上述的响应类主要来自于模块的django.http,该模块是实现响应功能的核心。
以 HttpResponse 为例,它的第一个参数是响应内容,一般是网页内容或 json 数据,网页内容是以 HTML 语言为主的,json 数据用于生成 API 接口数据。第二个参数用于设置 HTTP 状态码。从 HttpResponse 使用过程克制,如果要生成网页内容,就需要将 HTML 语言为字符串的形式表示,这并没有我们模版的作用。因此,Django 在此基础上进行了封装处理。定义了函数 render,redirect。
对 render 进行讲解。render 的语法如下:
render(request,template_name,context = None,content_type=None,status=None,using=None)
render 的参数 request 和 template_name 是必需参数
-
request:浏览器向服务器发送的请求对象,包含用户信息,请求内容和请求方式等
-
template_name:设置模版文件名,用于生成网页内容
-
context:对模版上下文(模版变量)赋值,以字典格式表示。默认情况下是一个空字典
-
context_type:响应内容的数据格式,一般情况下使用默认值即可
-
status:HTTP状态码,默认为200
-
using:设置模版引擎,用于解析模版文件,生成网页内容
在实际开发中,context 中一般会使用 python 内置语法 locals() ,locals() 会自动将函数里定义的变量传到模版文件中,并由模版引擎找到与之匹配的上下文。也就是说,在视图函数中所定义的变量名一定要与模版文件的上下文相同才能生效。
通过查看 render 的使用方法后,发现 render 的返回值调用响应类 HttpResponse 来生成具体的响应内容,这说明响应类 HttpResponse 是 Django 在响应过程中核心的功能类。
4.1.2 设置重定向
Django 的重定向类 HttpResponsePermanentRedirect、HttpResponseRedirect 以及重定向函数 redirect。
重定向的状态码分为 301 和 302,前者是永久性跳转的,后者是临时跳转的。两者的区别在于搜索引擎的抓取。301重定向是永久的重定向,搜索引擎在抓取新内容的同时会将旧的地址替换为重定向之后的网址。302跳转时暂时的跳转,搜索引擎会抓取新内容而保留旧的网址。
4.1.3 异常响应
异常响应是指 HTTP 状态码为 404 或 500 的响应状态码,它与正常的响应过程是一样的,只是 HTTP 状态码有所不同,因此使用函数 render 作为响应过程,并且设置参数 status 的状态码即可实现异常响应。
4.1.4 文件下载功能
响应内容除了返回网页信息外,还可以实现文件下载功能。Django中提供了三种方式实现文件下载功能,分别是 HttpResponse、StreamingHttpResponse 和 FileHttpResponse。三者的说明如下:
- HttpResponse 是所有响应过程的核心类,它的底层功能是 HttpResponseBase。
- StreamingHttpResponse 是在 HttpResponseBase 的基础上进行继承与重写的,它实现流式响应输出,适用于大规模响应和文件传输响应。
- FileResponse 是在 StreamingHttpResponse 的基础上进行继承与重写的,它实现文件的流式响应输出,只适用于文件传输响应。
4.2 HTTP 请求对象
网站是根据用户请求来输出相应的响应内容的,用户请求是指用户在浏览器上访问某个网页链接的操作,浏览器会根据网址链接信息向网站发送 HTTP 请求。那么,当 Django 接受到用户的请求时,它是如何获取用户请求信息的呢?
4.2.1 获取请求信息
当在浏览器上访问某个网址时,其实质是向网站发送一个 HTTP 请求,HTTP 请求分为8种请求方式:
请求方式 | 说明 |
---|---|
OPTIONS | 返回服务器针对特定资源所支持的请求方法 |
GET | 向特定资源发出请求 |
POST | 向指定资源提交数据处理请求 |
PUT | 向指定资源位置上传数据内容 |
DELETE | 请求服务器删除 request-URL 所标识的资源 |
HEAD | 与 GET 请求类似,返回的响应中没有具体内容,用于获取报头 |
TRACE | 回复和显示服务器收到的请求,用于测试和诊断 |
CONNECT | HTTP/1.1 协议中能够将连接改为管道方式的代理服务器 |
在上述的 HTTP 的请求方式里,最基本的是 GET 请求和 POST 请求。GET 请求和 POST 请求是可以设置请求参数的,两者的设置方式如下:
- GET 请求的请求参数是在路由地址后添加"?"和参数内容,参数内容以 key=value 形式表示,如果设计多个参数,每个参数之间需要使用"&"隔开。
- POST 请求的请求参数一般以表单的形式传递,常见的表单使用 HTML 的 form 标签,并且 form 标签的method属性设为 POST。
对于Django 来说,当它接收到 HTTP 请求之后,会根据 HTTP 请求携带的参数以及请求信息来创建一个 WSGIRequest 对象,并且作为视图函数的首个参数,这个参数通常写成 request ,该参数包含用户所有的请求信息。
4.2.2 Cookie 实现反爬虫
Django 接收的 HTTP 请求信息里带有 Cookie 信息,Cookie 的作用是为了识别当前用户的身份。Cookie 是从浏览器向服务器传递数据,让服务器能够识别当前用户,而服务器对 Cookie的识别机制是通过 Session 实现的,Session 存储了当前用户的基本信息,如姓名、年龄和性别等。由于 Cookie 存储在浏览器里面,而且 Cookie 的数据是由服务器提供的,如果服务器将用户信息直接保存在浏览器中,就很容易泄露用户信息,因此需要一种机制在服务器的某个域中存储用户数据,这个域就是 Session。
set_cookie 方法定义了 9 个函数参数,每个参数的说明如下:
- key:设置 Cookie 的 key,类似字典的 key
- value:设置 Cookie 的 value,类似字典的 value
- max_age:设置 Cookie 的有效时间,以秒为单位
- expires:设置 Cookie 的有效时间,以日期格式为单位
- path:设置 Cookie 的生效路径,默认值为根目录(网站首页)
- domin:设置 Cookie 生效的域名
- secure:设置传输方式,若为 False,则使用 HTTP ,否则使用 HTTPS
- httponly:设置是否只能使用 HTTP 协议传输
- samesite:设置强制模式,可选值为 lax 或 strict,主要防止 CSRF 攻击
常见的反爬虫主要是设置参数 max_age、expires 和 path。参数 max_age 或 expires 用于设置 Cookie 的有效性,使爬虫程序无法长时间爬取网站数据;参数 path 用于将 Cookie 的生成过程隐藏起来,不容易让爬虫开发者找到并破解。
Cookie 的数据信息一般都是经过加密处理的,若使用 set_cookie 方法设置 Cookie,则参数 value 需要自行加密,如果数据加密过于简单,就很容易被爬虫开发者破解,但是过于复杂又不利于日后的维护。Django 内置了 Cookie 的加密方法 set_signed_cookie。
在 Django 中,set_signed_cookied 方法用于设置一个带有签名的 Cookie,这种方法确保客户端和服务器之间传输时的安全性,因为只有知道正确签名密钥的服务器才能修改 Cookie 的内容。签名 Cookie 的加密盐是一个用于安全目的的随机字符串,它与 Cookie 的值一起用于生成签名,这个签名被附加到 Cookie 中,当浏览器发送 Cookie 回到服务器时,服务器会使用相同的盐和签名算法来验证 Cookie 的完整性。
set_signed_cookied 设有4个参数,参数说明如下:
- key:设置 Cookie 的 key,类似字典的key
- value:设置值
- salt:设置加密盐,用于数据的加密处理
4.2.3 请求头实现反爬虫
视图的参数 request 是由类 WSGIRequest 根据用户请求而生成的实例化对象。由于类 WSGIRequest 是继承并重写类 HttpRequest,而类 HttpRequest设置 META 属性,因此当用户在浏览器中访问 Django 时,会由 WSGI 协议实现两者的通信,浏览器的请求头信息来自类 WSGIRequest 的属性 environ,而属性 environ 来自类 WSGIHandler。总的来说,属性 environ 经过类 WSGIHandler 传递给类 WSGIRequest 。
上述提及的 WSGI 协议是一种描述服务器如何与浏览器通信的规范。Django 的运行原理就是在此规范上建立的。
HTTP 的请求头信息来自属性 environ,请求头信息是动态变化的,它可以自定义属性,因此常用于指定反爬虫机制。请求头信息只能由浏览器进行配置,服务器只能读取请求头信息,通过请求头实现的反爬虫机制一般需要借助前段的 AJAX 实现。