news 2026/10/22 2:53:57

Django+DRF接口开发与Jmeter测试实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Django+DRF接口开发与Jmeter测试实战

1. 项目整体思路:Django 接口与 Jmeter 测试该怎么搭

前后端分离的项目里,后端把接口写好只是第一步,真正让接口稳定可用,还得靠持续的测试。我这些年做接口开发,最常用的组合就是 Python Django 写接口、Jmeter 做测试。Django 本身自带 ORM、Admin、认证体系,再配上 Django REST Framework(简称 DRF),写一套规范的 JSON 接口非常顺手。Jmeter 则是开源工具里最老牌、最普及的那一类,不管团队有没有商业测试平台,装一个 Jmeter 就能把接口跑起来,功能测试、并发压测、参数化关联全都能干。这篇文章就从零开始讲:怎么用 Django 把接口写出来,再用 Jmeter 把这些接口完整测一遍。

先说适用范围。如果你接触过 Django 或者其它 Web 框架,但还没系统地测过自己的接口;或者你已经会用 Postman 手动调接口,但对批量测试和并发场景没把握,那这篇文章正好合适。我不打算给你堆概念,而是把整个流程拆成可以照着做的步骤:先搭接口,再搭测试计划,中间穿插那些自己踩过的坑和总结出来的技巧。

1.1 为什么是 Django + DRF + Jmeter

选型这件事,很多人喜欢追新框架,但在实际团队里,稳定和熟练才是第一位的。Django 的生态非常完整,用户认证、数据库迁移、后台管理这些日常工作都有现成的解决方案,不需要重复造轮子。DRF 在 Django 之上补足了序列化、视图集、认证策略这些接口开发能力,写接口时只需要关注业务逻辑本身。

Jmeter 则解决了"怎么证明接口能用"的问题。它不像 Postman 那样只适合单接口调试,而是可以一次性模拟几十个、几百个用户同时访问接口,观察响应时间、错误率、吞吐量。Jmeter 还支持从 CSV 文件读取测试数据,把同一个接口用不同的参数跑很多遍,排查特殊值、边界值的问题。这些能力在接口交付之前几乎是必需的。

1.2 接口需求梳理与测试目标

在动手写代码之前,最好先把要测试的接口清单列出来。我这次以一个模拟商城项目为例,设计三类核心接口:用户登录接口、商品列表接口、订单创建接口。登录接口负责验证身份并返回令牌;商品列表接口是典型的分页查询场景;订单创建接口则依赖前一步拿到的登录状态。这三类接口覆盖了"无状态接口"和"需要认证的接口",正好把 Jmeter 里的常见操作都串起来。

测试目标也要提前定清楚。功能层面,要确认每个接口在不同参数下的返回结果符合预期;性能层面,要确认在 50 个并发用户的情况下,接口平均响应时间在可接受范围内,并且没有请求丢失。有了明确目标,后面配置 Jmeter 时就知道该加哪些断言、跑多大的并发数,而不是漫无目的地乱测。

2. Django 端接口开发全流程

2.1 环境准备与依赖选型

开发接口时,我习惯为每个项目单独创建虚拟环境,避免不同项目之间的包版本互相干扰。创建虚拟环境的命令很简单,在项目目录下执行:

python -m venv venv source venv/bin/activate

激活虚拟环境之后,再安装依赖。核心依赖包括 Django、DRF 以及用于令牌认证的 djangorestframework-simplejwt。注意版本之间要匹配,我常用的组合是 Django 4.2 配 DRF 3.14,再配上 simplejwt 5.2,这套组合在实际项目中跑得很稳。安装命令如下:

pip install django djangorestframework djangorestframework-simplejwt

装完后,用 django-admin 创建项目和应用:

django-admin startproject shop_project cd shop_project python manage.py startapp shop

创建完成后,需要把上述依赖注册到项目的 settings.py 里。INSTALLED_APPS 中要加入 rest_framework、rest_framework_simplejwt 和 shop 应用。同时,为了让接口在测试时不被跨域问题拦住,还要安装 django-cors-headers 并在中间件里加上 CorsMiddleware。这个包在前后端分离开发中几乎必装,否则浏览器调试时会看到跨域报错。

2.2 模型与序列化器设计

写接口的本质是操作数据,所以先要把数据模型定义好。以商品和订单为例,我在 shop/models.py 里写下如下模型:

from django.db import models class Product(models.Model): name = models.CharField(max_length=100) price = models.DecimalField(max_digits=10, decimal_places=2) stock = models.IntegerField(default=0) created_at = models.DateTimeField(auto_now_add=True) class Order(models.Model): order_no = models.CharField(max_length=32, unique=True) product = models.ForeignKey(Product, on_delete=models.CASCADE) quantity = models.IntegerField() total_amount = models.DecimalField(max_digits=10, decimal_places=2) created_at = models.DateTimeField(auto_now_add=True)

定义好模型之后,执行python manage.py makemigrations和python manage.py migrate生成数据库表。这个步骤容易忘,实际开发中我经常写完模型忘记迁移,结果接口一调就报表不存在的错误。

序列化器是 DRF 的核心,它的作用是把 Python 对象转成 JSON,同时负责校验前端传来的参数。我在 shop/serializers.py 中加入 ProductSerializer 和 OrderSerializer。要注意的细节是,创建订单时需要对库存做校验,这部分逻辑放在序列化器的 validate 方法里,比如库存不足就直接抛 ValidationError。这样的设计能把校验逻辑收拢到一处,后续用 Jmeter 测试非法下单场景时,返回的错误信息是统一格式,方便断言。

2.3 视图与路由实现

DRF 提供了多种视图写法,简单接口用 APIView,涉及列表和详情操作可以用 ModelViewSet。我这里采用 APIView 配合装饰器的方式,代码更好理解,也方便在接口里加自定义逻辑。

用户在 shop/views.py 中实现登录接口、商品列表接口和创建订单接口:

from rest_framework.views import APIView from rest_framework.response import Response from rest_framework.permissions import IsAuthenticated from rest_framework_simplejwt.tokens import RefreshToken from .models import Product, Order from .serializers import ProductSerializer, OrderSerializer def get_tokens_for_user(user): refresh = RefreshToken.for_user(user) return { 'refresh': str(refresh), 'access': str(refresh.access_token), } class LoginView(APIView): def post(self, request): username = request.data.get('username') password = request.data.get('password') from django.contrib.auth import authenticate user = authenticate(username=username, password=password) if user is None: return Response({'code': 1, 'msg': '用户名或密码错误'}, status=400) return Response({'code': 0, 'data': get_tokens_for_user(user)}) class ProductListView(APIView): def get(self, request): products = Product.objects.all() serializer = ProductSerializer(products, many=True) return Response({'code': 0, 'data': serializer.data}) class OrderCreateView(APIView): permission_classes = [IsAuthenticated] def post(self, request): serializer = OrderSerializer(data=request.data, context={'request': request}) if serializer.is_valid(): order = serializer.save() return Response({'code': 0, 'data': OrderSerializer(order).data}) return Response({'code': 1, 'msg': serializer.errors}, status=400)

路由在 shop/urls.py 和项目根 urls.py 中注册。实际做项目时,我会把 auth 相关的 jwt 刷新接口直接用 simplejwt 自带的路由,省去自己实现。同时,为了让 Jmeter 测试登录后拿到 token 更顺手,登录接口返回结构必须是固定的 JSON 格式,不能随意改动字段名。

2.4 本地起服务并快速自测

写完视图和路由后,先本地把服务跑起来,确认基本功能正常,再去配置 Jmeter。启动命令是:

python manage.py runserver 0.0.0.0:8000

这一步我会先用 curl 做一次最小验证。比如登录接口:

curl -X POST http://127.0.0.1:8000/api/login/ -H "Content-Type: application/json" -d '{"username":"admin","password":"123456"}'

如果返回 JSON 里有 access 字段,就说明登录接口通了。商品列表接口用 GET 请求直接访问,确认能拿到商品数组。自测阶段建议确认三件事:第一,HTTP 状态码是否正确;第二,返回体里是否包含关键字段;第三,错误参数是否能返回统一错误结构。这三件事确认好,再进 Jmeter 时能少走很多弯路。

3. Jmeter 端测试计划设计与参数配置

3.1 Jmeter 安装与关键组件认知

Jmeter 是 Java 编写的工具,使用前需要确保本机装了 JDK,建议用 JDK 11 或 17。下载 Jmeter 后解压,进入 bin 目录,执行./jmeter启动图形界面。首次打开可能会看到一堆菜单选项,让人有点懵,但其实只需要关注几个核心组件:测试计划、线程组、取样器、监听器、配置元件、断言。

从功能上看,Jmeter 的组件可以这样理解:线程组相当于一群虚拟用户;取样器是具体发的请求,比如 HTTP 请求;配置元件是全局的参数设置,比如 HTTP 请求默认值、CSV 数据文件;断言用于判断响应是否符合预期;监听器负责收集和展示结果。一个完整的测试计划,就是把这些组件按层次组织在一起。

3.2 线程组与 HTTP 请求默认值设置

新建测试计划后,第一步是添加线程组。右键测试计划,选择添加 -> 线程 -> 线程组。线程组里最重要的三个参数是线程数、Ramp-Up 周期、循环次数。线程数表示同时模拟多少个用户,Ramp-Up 周期表示在多少秒内启动这些线程,循环次数表示每个线程执行几遍测试。第一次做功能测试时,我习惯把线程数设为 1,循环次数设为 1,先把单条请求调通。

接下来是 HTTP 请求默认值。这个组件特别适合多接口测试,因为它可以把共同的协议、域名、端口集中配置。右键线程组,选择添加 -> 配置元件 -> HTTP 请求默认值,填入服务器名称或 IP,比如 127.0.0.1,端口填 8000,协议填 http。这样后面添加多个 HTTP 请求时,只需要填路径和参数,不用每个取样器都重复写一遍域名。这个设置能大幅减少配置工作量,也避免因为某个请求漏填域名而测到错误地址。

3.3 接口参数化:CSV 数据集配置

接口测试不能只用固定的账号和商品数据,否则测不出边界问题。Jmeter 支持通过 CSV 数据集配置把外部文件中的数据读入测试计划。我先准备一个 test_users.csv 文件,每一行包含用户名、密码、预期结果三列:

admin,123456,0 testuser,wrongpass,1

在 Jmeter 中右键线程组,添加 -> 配置元件 -> CSV 数据集配置。文件名填 CSV 的绝对路径,变量名称填 username,password,expect_code,分隔符用逗号,文件编码用 UTF-8。这样在 HTTP 请求里就可以用${username}和${password}引用当前行的数据。

这个过程的好处是,测试数据和测试脚本分离。修改测试数据不需要动 Jmeter 的脚本结构,而且同一个脚本可以用于不同环境、不同数据集的回归测试。比如我经常把线上环境的脱敏数据导出来,灌到 CSV 里直接跑一轮冒烟测试。

3.4 断言与结果监听器配置

没有断言的接口测试,只能算"发请求",不能算"验证接口"。Jmeter 中的断言组件里,最常用的是响应断言,它可以检查响应文本中是否包含指定的字符串。比如登录接口,我可以断言响应中是否出现"code": 0,如果出现就说明登录成功;再配合返回码断言,检查 HTTP 状态码是否为 200。

实际操作中,我还会加一个 JSON 断言。在较新的 Jmeter 版本里,添加 -> 断言 -> JSON 断言 可以直接用 JsonPath 表达式提取返回字段并校验。比如检查$.code是否等于 0,比字符串断言更精确,也不会因为字段顺序不同而误报。把多个断言叠加在同一个请求下,能对接口形成强校验。

结果监听器方面,最基础的是查看结果树和聚合报告。查看结果树可以看到每个请求的请求头、响应数据、断言结果,适合接口调试阶段使用。聚合报告则汇总了所有请求的平均响应时间、中位数、90% 响应时间、错误率、吞吐量,适合性能评估。我通常会在调试阶段打开查看结果树,在最终跑测试计划时把它禁用掉,只开聚合报告,因为查看结果树会占用大量内存,尤其是并发线程多的时候。

4. 登录令牌提取与接口关联实现

4.1 用 JSON 提取器拿到 token

实际业务中,订单创建这类接口需要携带用户登录后返回的令牌。在 Jmeter 里,可以用后置处理器把登录接口返回的 token 提取出来,传给后续请求。整个过程叫"关联",这一步做得好,测试计划才能真正串联起来。

在登录请求下面,右键添加 -> 后置处理器 -> JSON 提取器。由于登录接口返回的是{"code":0,"data":{"access":"...","refresh":"..."}},所以 JsonPath 表达式填$.data.access,变量名填access_token,匹配数量填 1。执行登录请求后,token 就会自动保存到access_token变量中,供其它请求引用。

这里有个实际经验:simplejwt 返回的 access token 默认有效期是 5 分钟,如果测试计划运行时间比较长,后续请求可能会遇到 401 认证失败。解决思路有两个,要么在 Jmeter 里增加一个"刷新 token"的请求,要么在 Django 端把 access token 的过期时间调长一点。开发环境我一般调长,测试环境会单独写刷新请求来模拟真实场景。

4.2 令牌传递与多接口串联测试

拿到 token 之后,需要把它放到 HTTP 请求头中。右键添加 -> 配置元件 -> HTTP 头管理器,然后新建一个请求头,名称填 Authorization,值填Bearer ${access_token}。注意 token 之间必须有空格,否则服务端解析请求头时可能报错。我用 Jmeter 时见过不少人忘了空格,导致接口一直 401。

配置好之后,订单创建请求的完整链路就是:登录请求 -> 提取 token -> 携带 token 创建订单。整个测试计划按顺序执行,就能模拟一个真实用户从登录到下单的完整操作。如果把线程数调成 50,再设置好 Ramp-Up 时间,就变成了 50 个用户同时走"登录->下单"流程,这种场景对发现接口并发问题特别有效。

4.3 并发场景下的注意事项

说到并发,Jmeter 模拟并发时有个经典陷阱:每个线程组里的线程会按照同样的逻辑执行请求,也就是说 50 个线程会各自独立地执行"登录->下单"链路,互不干扰。但订单表里 order_no 字段是唯一键,如果下单接口没有做唯一性处理,比如基于时间戳生成订单号,并发时容易碰撞,导致部分请求报唯一键冲突。所以我会在 Django 端用 uuid 生成订单号,保证并发场景下不会重复。

另外,Jmeter 默认每个虚拟用户不会自动使用不同的数据。只要你在 CSV 数据集配置里打开了共享模式设置,配置为"当前线程组"或"所有线程",每个线程读取到的数据行就会不同。如果不配置,多个线程可能读到同一行数据,导致重复提交。并发测试前,CSV 的数据行数最好大于线程数,避免数据被读空。

5. 常见问题与故障排查实录

5.1 403 与 CSRF 校验问题

Django 自带 CSRF 防护,会拦截 POST 请求中不带 CSRF token 的请求。用 Jmeter 直接发 POST 请求时,最容易撞到的问题就是 403 Forbidden。解决办法是,在接口视图上加上@csrf_exempt装饰器,或者在 Django 设置中配置 DRF 的认证方式时,把 CSRF 校验排除在接口路由之外。实际操作中,我倾向于在接口路由层面统一处理,避免每个视图都添加装饰器,显得很啰嗦。

如果测试的是已有项目,不想改动后端代码,也可以在 Jmeter 中先发一个 GET 请求拿到 CSRF cookie,再通过 Cookie 管理器把请求带过去,但这种方式麻烦且没必要。我的建议是:纯 JSON API 的 POST 请求,直接在 Django 端关闭 CSRF,因为接口场景本身是给程序调用的,不是给浏览器表单用的。

5.2 连接拒绝、超时与编码问题

Jmeter 报 Connection refused,大概率是服务没启动或端口不对。先确认 Django runserver 进程还在,再确认 HTTP 请求默认值里的端口与 runserver 的端口一致。还有种情况是 Jmeter 所在机器和 Django 服务不在同一台机器上,此时服务器 IP 不能写成 127.0.0.1,要写成 Django 服务所在机器的局域网 IP,并且 Django 启动时要监听 0.0.0.0。

响应中文乱码是另一个常见问题。Django 返回的 JSON 如果包含中文,Jmeter 查看结果树时可能显示成乱码。解决办法是在 Jmeter 的 jmeter.properties 或 user.properties 中,把默认编码改为 UTF-8。不过更稳妥的做法是在接口返回时,让 DRF 统一输出 Unicode 转义或者确保响应头包含charset=utf-8。我在实际项目里会直接设置 DRF 的 renderer 类,确保所有响应都是 UTF-8 编码。

5.3 常见问题速查表

现象可能原因解决方案
403 ForbiddenCSRF 校验未关闭在视图或路由层排除 CSRF
401 Unauthorizedtoken 缺失或过期检查 HTTP 头管理器中的 Authorization 格式
Connection refused服务未启动或端口错误确认 Django 服务状态和端口配置
中文乱码编码未统一为 UTF-8调整 Jmeter 默认编码或 DRF 响应头
断言失败返回结构变化或字段名不匹配查看结果树中实际响应,修改断言表达式
并发下单报错订单号重复后端改用 uuid 生成订单号

这张表基本覆盖了我做接口测试时遇到的绝大多数问题。有些问题看起来是 Jmeter 配置的问题,实际是后端接口设计没有考虑测试场景。开发接口时如果多想想"测试工具会怎么调用我",很多坑都能在源头避开。

5.4 调试前的排查思路

遇到接口测试异常时,我有一套固定的排查顺序,能省下不少时间。第一步,打开查看结果树,看响应体里到底返回了什么,很多问题一眼就能看出来。第二步,用 curl 直接请求同一接口,排除 Jmeter 侧干扰。如果 curl 正常而 Jmeter 异常,问题多半在请求头、环境变量或编码上;如果 curl 也异常,那就是后端代码的问题。第三步,检查 Jmeter 日志文件,这个文件记录了所有取样器的错误明细,比界面上的提示更完整。

这套排查思路看起来简单,但实际操作中很多人会跳着来,直接改代码改配置,结果越改越乱。按顺序排查,至少能保证每次只改一个变量,出问题也知道是哪个改动引起的。

6. 进阶扩展:测试数据准备与性能测试参数调优

6.1 测试数据准备策略

做接口测试时,测试数据往往比测试脚本更花时间。对于 Django 接口,我建议直接用 Django 的 Fixture 或者 ORM 批量生成测试数据。可以在应用目录下写一个 management command,批量创建几百条商品记录和测试账号,这样 Jmeter 压测时才有足够的数据可以查。

比如创建一个 Django management command,用 Faker 库生成 1000 条商品名称随机数据。这个命令可以重复执行,不会因为数据重复而报错。有了批量数据后,商品列表接口的分页、排序、搜索功能才能真正测到位。没有数据支撑的接口测试,拿到手的结果意义很有限。

6.2 性能测试参数调优

性能测试的核心是找到接口的瓶颈,而不是追求某个固定的并发数。先把线程数设成 10,跑一轮,看聚合报告里的平均响应时间和错误率;再逐步增加到 50、100,观察曲线变化。如果响应时间随并发数线性上涨且错误率上升,基本可以判断接口存在瓶颈,比如数据库连接池不够、查询没有走索引等。

Jmeter 里有一个很有用的指标叫吞吐量,单位是每秒请求数。这个指标能直观地反映系统处理能力。需要注意的是,吞吐量不是越高越好,而是要结合响应时间和错误率一起看。如果吞吐量上去了,但响应时间劣化严重,用户体验会很差。性能测试的结论,永远要综合三个指标来看,单看哪个都容易误判。

6.3 对 Django 端的反向优化建议

Jmeter 测出来的性能问题,很多可以反推回 Django 端优化。比如商品列表接口响应慢,可以在 Django Debug Toolbar 里看执行的 SQL 数量,如果存在 N+1 查询,就用select_related或prefetch_related把关联查询合并。数据库索引缺失也是常见问题,对乘积WHERE查询的字段加索引,性能提升非常显著。

我通常的做法是:先用 Jmeter 跑出基线数据,然后在 Django 端做一次优化,再用 Jmeter 跑第二遍对比前后数据。这种"测试-优化-回归"的循环,是接口质量提升最有效的方式。Jmeter 不只是用来交差的,它能把优化的效果量化出来,让每一次改动都有数据支撑。

我个人在实际操作中的体会是,接口开发与测试是一件事的两面,开发时把可测性考虑进去,测试时把业务逻辑理解到位,两边配合才能把接口质量真正提上去。先把 CSV 参数化跑熟,再去做令牌关联和并发,Jmeter 的学习曲线并没有想象中那么陡。后续如果团队规模再大一点,还可以把 Jmeter 脚本接入 CI 流程,用命令行模式jmeter -n -t script.jmx -l result.jtl定时跑回归测试,把接口测试从手工操作变成自动化任务,那又是另一个值得记录的话题了。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/22 2:53:48

语音增强毕设难在数据管线:切段、列表划分与PESQ评测

简介:面向计算机类毕业设计与课程作业的深度学习语音增强与去混响项目包,针对噪声和混响环境下语音质量提升问题,提供完整的系统实现方案。压缩包内共144个文件,主要包含Python源码、C相关代码、MATLAB脚本、文本配置与数据列表、…

作者头像 李华
网站建设 2026/10/22 2:52:56

Java SSM实现社区健康档案管理平台:从数据库设计到论文答辩全解析

社区健康档案管理这个题目,在Java Web方向的毕设和实训项目里可以说是常青树。不是因为它多高级,而是业务边界清楚、角色划分明确、数据模型也足够典型,前前后后该有的CRUD、权限、统计、报表、导出全都能练到。我用SSM这套组合完整跑过一版&…

作者头像 李华
网站建设 2026/10/22 2:52:53

Unity动画核心解析:Animation与Animator状态机及参数驱动

1. Animation和Animator的关系:先把这套系统看明白再动手平时经常有同学问我:“Unity里的动画到底应该用Animation还是Animator?”甚至有人以为这两个是同一种东西的两种叫法,直接把组件拖上去随便弄,然后动画怎么都不…

作者头像 李华
网站建设 2026/10/22 2:51:33

Win11右键菜单太麻烦?注册表一键恢复Win10经典样式

用 Windows 11 的朋友应该都有这种经历:在桌面或文件夹里右键,弹出来的不再是以前那种一长串完整菜单,而是顶部一排图标、底部一个“显示更多选项”的精简面板。对鼠标用户来说,这个改动最大的问题不是好不好看,而是原…

作者头像 李华
网站建设 2026/10/22 2:51:02

Linux硬件排障必会:lspci命令详解与PCIe总线诊断实战

一次硬件排障的经历让我彻底离不开 lspci 这条命令。当时一台工作站新装了一块显卡,开机后显示器完全没信号,第一反应是显卡坏了,第二反应是供电不够。折腾了半天,最后在系统里跑了一下 lspci,发现设备根本没有被系统枚…

作者头像 李华
网站建设 2026/10/22 2:50:21

FPGA实现双路FM语音接收机:数字通信系统实战指南

简介:本资源是2019年全国大学生电子设计竞赛G题‘双路语音调频接收机’的FPGA全功能实现方案,面向电子类、通信类专业本科生及FPGA初学者,解决高频信号接收、双通道语音解调与硬件协同设计等典型赛题难点。压缩包共87个文件,涵盖2…

作者头像 李华