将软件(Software)、平台(Platform)、基础设施(Infrastructure)封装为服务(Service),是当下多数 IT 企业的核心实践方向,这也是大家熟知的 SaaS(软件即服务)、PaaS(平台即服务)和 IaaS(基础设施即服务)的核心逻辑。面向服务架构(SOA)的实现方式多种多样,RPC(远程过程调用)、Web Service、REST 等均是主流方案;从技术维度看,SOA 是一种抽象化、松耦合的粗粒度软件架构,而从业务维度来讲,其核心是 “复用” 与 “互操作”—— 将系统资源整合为标准化、可调用的服务,实现资源的灵活重组与复用。在众多 SOA 实现方案中,REST 因适配互联网应用的特性成为首选,符合 REST 规范的架构也被称为 RESTful 架构。
REST 这一概念由 Roy Thomas Fielding 在 2000 年的博士论文中提出,他不仅是 HTTP 协议(1.0 和 1.1 版本)的核心设计者,还是 Apache 服务器软件的主要开发者、Apache 基金会首任主席。在这篇论文中,Roy 将互联网软件的架构原则命名为 REST,即 REpresentational State Transfer 的缩写,中文常译作 “表现层状态转移”(也译作 “表述状态转移”)。
这里的 “表现层”,本质是 “资源” 的表现形式。所谓 “资源”,指的是网络中的一个实体或具体信息,比如一段文本、一张图片、一首音频,甚至是一项服务。每个资源都可以通过 URI(统一资源定位符)唯一标识,访问该 URI 即可获取对应的资源。同一资源可呈现多种形式,这种具体的呈现方式就是 “表现层”:例如文本可采用 text/plain、text/html、text/xml、application/json 等格式,图片可采用 image/jpeg、image/png 等格式。
需要注意的是,URI 仅标识资源本身,而非其表现形式。严格来说,网址末尾的.html后缀并无必要 —— 该后缀属于 “表现层” 范畴,而 URI 应仅指向 “资源” 的位置;资源的具体表现形式,应通过 HTTP 请求头中的Accept 和 Content-Type 字段指定,这两个字段才是对 “表现层” 的精准描述。
客户端与服务器的交互过程,本质是数据和状态的变更过程。Web 应用通常基于 HTTP 协议通信,客户端通过 HTTP 请求触发服务器的 “状态转移”,而这种转移基于资源的表现层完成,因此称为 “表现层状态转移”。客户端可通过 HTTP 动词(GET、POST、PUT/PATCH、DELETE)实现对资源的四类核心操作:
简言之,RESTful 架构的核心是:“每个 URI 对应一种资源,客户端通过四种 HTTP 动词操作服务器端资源,实现资源的表现层状态转移”。
设计 RESTful 架构的第一步,是采用符合 REST 风格的 URI 对外提供资源,但真正的 RESTful 架构还需满足 “无状态” 和 “幂等性” 两大核心特性(后续会详细讲解)。以下是 REST 风格 URI 的示例,供设计参考:
| GET | /students/ | |
| POST | /students/ | |
| GET | /students/ID/ | |
| PUT | /students/ID/ | |
| PATCH | /students/ID/ | |
| DELETE | /students/ID/ | |
| GET | /students/ID/friends/ | |
| DELETE | /students/ID/friends/ID/ |
在 Django 项目中实现 REST 架构,对外提供 REST 风格的 API 接口,最常用的第三方库是 djangorestframework(简称 DRF)。
安装DRF执行以下命令完成 DRF 的安装:
pip install djangorestframework配置DRF在 Django 项目的 settings.py 文件中,将 DRF 添加到 INSTALLED_APPS,并根据业务需求配置相关参数:
INSTALLED_APPS = ['rest_framework',]# 下面的配置根据项目需要进行设置REST_FRAMEWORK = {# 配置默认页面大小# 'PAGE_SIZE': 10,# 配置默认的分页类# 'DEFAULT_PAGINATION_CLASS': '...',# 配置异常处理器# 'EXCEPTION_HANDLER': '...',# 配置默认解析器# 'DEFAULT_PARSER_CLASSES': (# 'rest_framework.parsers.JSONParser',# 'rest_framework.parsers.FormParser',# 'rest_framework.parsers.MultiPartParser',# ),# 配置默认限流类# 'DEFAULT_THROTTLE_CLASSES': (# '...'# ),# 配置默认授权类# 'DEFAULT_PERMISSION_CLASSES': (# '...',# ),# 配置默认认证类# 'DEFAULT_AUTHENTICATION_CLASSES': (# '...',# ),}前后端分离开发模式下,后端需向前端 / 移动端提供 JSON 格式的 API 数据,这就需要对模型对象进行序列化处理。DRF 封装了 Serializer 和 ModelSerializer 类,通过继承这两个类可自定义序列化器,将模型对象转换为字典格式。示例代码如下:列化器,用于将对象处理成字典,代码如下所示。
from rest_framework import serializers classSubjectSerializer(serializers.ModelSerializer):classMeta: model = Subject fields = '__all__'上面的代码直接继承了ModelSerializer,通过Meta类的model属性指定要序列化的模型以及fields属性指定需要序列化的模型字段,稍后我们就可以在视图函数中使用该类来实现对Subject模型的序列化。
DRF 支持两种接口实现方式:FBV(基于函数的视图)和 CBV(基于类的视图)。先以 FBV 为例实现数据接口:
from rest_framework.decorators import api_viewfrom rest_framework.response import Response@api_view(('GET', ))defshow_subjects(request: HttpRequest) -> HttpResponse: subjects = Subject.objects.all().order_by('no')# 创建序列化器对象并指定要序列化的模型 serializer = SubjectSerializer(subjects, many=True)# 通过序列化器的data属性获得模型对应的字典并通过创建Response对象返回JSON格式的数据return Response(serializer.data)相较于传统的 bpmapper 序列化方式,DRF 的代码更简洁,且自带可视化接口调试页面,便于接口测试与调试。

直接使用上一节写好的页面,就可以通过Vue.js把上面接口提供的学科数据渲染并展示出来,此处不再进行赘述。
步骤 1:编写序列化器
classSubjectSimpleSerializer(serializers.ModelSerializer):classMeta: model = Subject fields = ('no', 'name')classTeacherSerializer(serializers.ModelSerializer):classMeta: model = Teacher exclude = ('subject', )步骤 2:编写视图函数
@api_view(('GET', ))defshow_teachers(request: HttpRequest) -> HttpResponse:try: sno = int(request.GET.get('sno')) subject = Subject.objects.only('name').get(no=sno) teachers = Teacher.objects.filter(subject=subject).defer('subject').order_by('no') subject_seri = SubjectSimpleSerializer(subject) teacher_seri = TeacherSerializer(teachers, many=True)return Response({'subject': subject_seri.data, 'teachers': teacher_seri.data})except (TypeError, ValueError, Subject.DoesNotExist):return Response(status=404)步骤 3:配置 URL 映射在项目的 urls.py 中添加接口路由:
urlpatterns = [ path('api/teachers/', show_teachers),]步骤 4:Vue.js 前端渲染以下是基于 Vue.js 的前端页面示例,用于渲染老师信息接口返回的数据:
<!DOCTYPE html><htmllang="en"><head><metacharset="UTF-8"><title>老师信息</title><style>/* 此处省略掉层叠样式表 */</style></head><body><divid="container"><h1>{{ subject.name }}学科的老师信息</h1><hr><h2v-if="loaded && teachers.length == 0">暂无该学科老师信息</h2><divclass="teacher"v-for="teacher in teachers"><divclass="photo"><img:src="'/static/images/' + teacher.photo"height="140"alt=""></div><divclass="info"><div><span><strong>姓名:{{ teacher.name }}</strong></span><span>性别:{{ teacher.sex | maleOrFemale }}</span><span>出生日期:{{ teacher.birth }}</span></div><divclass="intro">{{ teacher.intro }}</div><divclass="comment"><ahref="" @click.prevent="vote(teacher, true)">好评</a> (<strong>{{ teacher.good_count }}</strong>) <ahref="" @click.prevent="vote(teacher, false)">差评</a> (<strong>{{ teacher.bad_count }}</strong>)</div></div></div><ahref="/static/html/subjects.html">返回首页</a></div><scriptsrc="https://cdn.bootcdn.net/ajax/libs/vue/2.6.11/vue.min.js"></script><script>let app = newVue({el: '#container',data: {subject: {},teachers: [],loaded: false },created() {fetch('/api/teachers/' + location.search) .then(resp => resp.json()) .then(json => {this.subject = json.subjectthis.teachers = json.teachers }) },filters: {maleOrFemale(sex) {return sex? '男': '女' } },methods: {vote(teacher, flag) {let url = flag? '/praise/' : '/criticize/' url += '?tno=' + teacher.nofetch(url).then(resp => resp.json()).then(json => {if (json.code === 10000) {if (flag) { teacher.good_count = json.count } else { teacher.bad_count = json.count } } }) } } })</script></body></html>HTTP 协议本身是无状态的 —— 一次请求完成后连接断开,服务器无法识别后续请求的用户身份。但 Web 应用需要会话管理来跟踪用户状态,从而实现权限控制和个性化服务。
传统的会话管理方式是基于 Session 实现:用户登录成功后,服务器创建 Session 对象存储用户信息,将 Session ID 写入浏览器 Cookie;后续请求时,服务器通过 Cookie 中的 Session ID 找到对应的 Session 对象,获取用户数据。但这种方式与 REST 架构的 “无状态” 特性冲突 —— 服务器存储 Session 会增加水平扩展的难度(新增服务器节点需同步 Session 数据)。
解决该问题的方案主要有两种:1.引入 Redis 等缓存服务器,集中存储 Session,实现多节点共享;2. 放弃 Session,采用基于 Token 的用户跟踪方案。
基于 Token 的用户跟踪无需服务器存储用户状态,更适配 RESTful 架构的无状态特性,核心流程如下:
localStorage/sessionStorage/Cookie,Vue 项目也可通过 Vuex 管理);生成 Token 的主流方案是 JSON Web Token(JWT),下面详细讲解 JWT 的使用。
JSON Web Token(JWT)是基于 RFC 7519 标准的令牌规范,是 RESTful 架构下用户认证的主流方案。JWT 由三部分组成,各部分通过.分隔,分别是头部(Header)、载荷(Payload)和签名(Signature)。

{"alg":"HS256","typ":"JWT"}alg:指定签名算法,默认 HMAC SHA256(简写为 HS256);typ:令牌类型,固定为 JWT。自定义字段示例
```JSON{ "sub": "1234567890", "nickname": "jackfrued", "role": "admin"}```签名用于验证令牌的完整性,防止篡改。生成签名需满足以下条件:
HS256(base64Encode(header) + '.' + base64Encode(payload), secret)最终将 Header、Payload、Signature 三部分用.拼接,即生成完整的 JWT 令牌。
优点
Python 中可通过 PyJWT 库实现 JWT 的生成与验证,步骤如下:
pip install pyjwtpayload = {'exp': datetime.datetime.utcnow() + datetime.timedelta(days=1),'userid': 10001}token = jwt.encode(payload, settings.SECRET_KEY).decode()try: token = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE1OTQ4NzIzOTEsInVzZXJpZCI6MTAwMDF9.FM-bNxemWLqQQBIsRVvc4gq71y42I9m2zt5nlFxNHUo' payload = jwt.decode(token, settings.SECRET_KEY)except InvalidTokenError:raise AuthenticationFailed('无效的令牌或令牌已经过期')如果不清楚JWT具体的使用方式,可参考之前的内容,里面提供了完整的投票项目代码的地址。
国内直接使用顶级AI工具
谷歌浏览器访问:
https://www.nezhasoft.cloud/r/vMPJZr
