REST 代表的是表现层状态转移(REpresentational State Transfer),REST 本身并没有创造新的技术、组件或服务,它只是一种软件架构风格,是一组架构约束条件和原则,而不是技术框架,REST 有一系列规范,满足这些规范的 API 均可称为 RESTful API。
了解和掌握RESTful API的规范,有助于提升程序员的软实力,REST 架构对资源的操作包括获取、创建、修改和删除,这些操作正好对应 HTTP 协议提供的 GET、POST、PUT 和 DELETE 方法。简单来说,RESTful API就是前后端接口对接的规范。
RESTful API 设计原则
主要用来进行RESTful API 设计原则落地的是两个关键点:URI 设计 和 HTTP Method,通过URI和HTTP Method 更好的理解Api的作用和功能,开发人员在浏览文档、对接接口的时候更加简洁、方便和高效。( 话外之音是前后端分离开发的模式下,咱俩这样约定好规范 )
URI 设计
资源都是使用 URI 标识的,我们应该按照一定的规范来设计URI,通过规范化可以使我们的 API 接口更加易读、易用。以下是 URI 设计时,应该遵循的一些规范:
- 资源名使用名词而不是动词,并且用名词复数表示,下面的接口都是
menus。 - URI 结尾不应包含
/,URI 中最好不要出现下划线 ( 我个人觉得下划线不够友好 ) - URI 路径用小写,不要用大写。
- 避免层级过深的 URI,超过 2 层的资源嵌套会很乱,建议将其他资源转化为传递的参数
bash
GET /api/admin/menus?page=1
PUT /api/admin/menus/1
DELETE /api/admin/menus/2
POST /api/admin/menus
GET /api/admin/menus?title=权限管理&tab=all&category_id=5
HTTP Method 规范
基本上 RESTful API 都是使用 HTTP 协议原生的 GET、PUT、POST、DELETE 来标识对资源的 CRUD 操作的,在 RESTful API 设计中,资源(Resource) 是核心抽象,我们通常把资源分为两类:Collection 资源(集合资源)和 Member 资源(成员 / 单个资源)
| HTTP 方法 | Collection 资源 | Member 资源 | 是否安全 | 是否幂 |
|---|---|---|---|---|
| GET | /admin/menus 获得整个菜单数据集合 | /admin/menus/1 集合中的单个实例,一般这个后面是ID | 是 | 是 |
| PUT | /admin/menus/1 更新数据 | 更新数据中某些属性 | 否 | 否 |
| POST | /admin/menus 保存数据 | 没有这类操作 | 否 | 是 |
| DELETE | /admin/menus/2 删除资源 | 删除某个资源 | 否 | 是 |
在这里有几点是我自己总结的,和需要注意的地方:
- 有些地方更新数据使用PATCH方法,但我觉得更新属性使用PUT方法即可,没有必要使用PATCH
- 相同资源要统一字段名称,GET 返回的结果,要尽量可用于 PUT、POST 操作中。
- POST 方法仅用来创建或者批量删除这两种场景,批量删除通常是多条数据,传递数组更加安全和保险。
- 删除单条数据统一使用DELETE方法。
下面是段使用PHP编写的代码实例,这是在路由上区别资源的方法、功能和作用,使路由更加简捷、方便。
php
# 角色模块
Route::group('roles', static function () {
Route::get('', 'role/roles');
Route::post('', 'role/add');
Route::delete(':roleId', 'role/delete');
Route::put(':roleId/menus', 'role/saveMenus');
Route::put(':roleId/status', 'role/status');
Route::put(':roleId', 'role/update');
});
# 菜单模块
Route::group('menus', static function () {
Route::get('', 'menu/menus');
Route::delete(':menuId', 'menu/delete');
Route::post('', 'menu/add');
Route::put(':menuId/status', 'menu/status');
Route::put(':menuId', 'menu/update');
});
通过URI方式拼接好的路径在使用上也更加方便,代码如下:
php
public function status(int $menuId): \think\response\Json
{
$status = $this->request->put('status/d','','trim');
if(empty($menuId) || empty($status)){
return show(config('status.empty.code'),config('status.empty.message'));
}
$data = [
'menu_status' => $status,
'update_time' => date('Y-m-d H:i:s'),
'update_admin_id' => $this->adminInfo['admin_id'],
'update_admin_name' => $this->adminInfo['admin_name'],
];
$rbacService = new RbacService();
$rows = $rbacService->editMenu($menuId,$data);
if($rows) {
return show($this->successCode,$this->successMessage);
}else{
return show($this->errorCode,$this->errorMessage);
}
}
统一返回格式
一个规范的 RESTful API 返回格式,通常包含 状态元数据 和 业务数据 两大部分,同时要结合 HTTP 状态码一起使用(而非仅靠自定义码)。
1. 基础通用结构(JSON 格式)
这是业界最常用、最易扩展的统一格式,你可以直接参考使用:
php
{
"code": 200, // 自定义业务状态码(核心)
"message": "success", // 可读的状态描述(成功/失败原因)
"data": {}, // 业务数据(成功时返回,失败时可为null/{})
"timestamp": 1742195945000, // 请求处理时间戳(毫秒),便于排查问题
"requestId": "req-8a4501c37657" // 请求唯一标识,便于链路追踪
}
2.成功场景,单条的直接在data下面,多条的在list下面。
php
{
"code": 200,
"message": "操作成功",
"data": {
"list": [
{
"role_id": 1,
"role_name": "超级管理员"
},
{
"role_id": 2,
"role_name": "运营"
}
],
"total": 3
}
}
这里的业务状态码是根据自己的业务而划定,比如1000 开头的都属于用户验证信息相关 ,2000开头的都属于权限相关的。
php
//用户验证信息相关
'accountEmpty' => [
'code' => 1001,
'message' => '后台用户账号不能为空',
],
'passwordEmpty' => [
'code' => 1002,
'message' => '后台用户密码不能为空',
],
//组织架构、权限相关
'exist' => [
'code' => 2001,
'message' => '角色名称已存在',
],
优点
1. 通用性强,易于理解和使用
RESTful API 基于 HTTP 协议的原生特性设计,比如用GET(查询)、POST(新增)、PUT(全量更新)、DELETE(删除) 等请求方法表达操作语义,用 URL 表示资源(而非操作)。
市面上大部分的开发都是前后端分离的模式来开发,无论开发语言(Java/Python/Go)、客户端类型(前端 / 移动端 / 第三方系统),开发者都能基于 HTTP 常识快速理解和调用 API,降低学习成本和沟通成本。
2.无状态,高可扩展性
RESTful API 要求无状态 :以前的web开发的会话管理大部分依赖Cookie 和 Session ,后来分布式和微服务发展后无状态的会话管理更有利于业务的需求,所以服务器不保存客户端的会话信息,每个请求都包含完成该请求所需的全部信息(比如通过 JWT 传递身份信息)。
3.可缓存,提升性能
RESTful API 充分利用 HTTP 的缓存机制(如Cache-Control、ETag响应头):客户端可缓存 GET 请求的结果,重复请求时直接使用缓存,减少网络传输和服务器压力,在之前的工作经验中部门内没有规则,同学们都是各写各的,搞的十分头疼,如果是RESTful API 风格统一,这样就可以在Nginx添加缓存,在Http请求入口出多了一个可以优化性能的点。
以下是一个针对 HTTP GET 请求接口启用 20 分钟缓存的 Nginx 配置示例,包含了详细的参数说明和功能注释。该配置使用 proxy_cache 模块对后端动态接口进行缓存,仅对 GET 和 HEAD 方法生效,缓存时长为 20 分钟(1200 秒)。
bash
# 在 http 块中定义缓存路径和相关参数
http {
# 缓存存放路径及共享内存区域定义
proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=my_cache:10m max_size=1g inactive=60m use_temp_path=off;
# 参数说明:
# - /var/cache/nginx : 缓存文件存放的本地目录
# - levels=1:2 : 缓存目录层级(减少单目录文件过多)
# - keys_zone=my_cache:10m : 定义共享内存区域名称(my_cache)和大小(10MB),用于存储缓存键和元数据
# - max_size=1g : 缓存数据最大占用磁盘空间为 1GB
# - inactive=60m : 如果缓存的数据在 60 分钟内未被访问,则自动删除(即使未过期)
# - use_temp_path=off : 避免将临时文件写入 proxy_temp 目录,直接写入缓存目录,提升性能
server {
listen 80;
server_name www.work.com;
# 对需要缓存的 API 接口进行配置(例如所有以 /api/ 开头的请求)
location /api/ {
# 启用缓存,并指定使用上面定义的共享内存区域
proxy_cache my_cache;
proxy_cache_methods GET HEAD;
proxy_cache_key $scheme$host$request_uri;
# 针对不同响应码设置缓存有效期
proxy_cache_valid 200 302 20m; # 状态码 200 和 302 缓存 20 分钟
# 当请求包含特定头或参数时,跳过缓存(常用于开发/调试)
# 例如,如果请求头中有 "X-No-Cache" 或者查询字符串包含 "nocache",则直接透传至后端
proxy_cache_bypass $http_x_no_cache $arg_nocache;
proxy_no_cache $http_x_no_cache $arg_nocache;
# 向客户端发送缓存命中状态(响应头中会显示 X-Proxy-Cache: HIT/MISS)
add_header X-Proxy-Cache $upstream_cache_status;
# 可选:设置请求头,向后端传递客户端真实 IP 等信息
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# 后端服务地址(示例)
proxy_pass http://backend_server;
# 其他代理相关配置(如超时、缓冲等)
proxy_connect_timeout 5s;
proxy_read_timeout 10s;
proxy_send_timeout 10s;
}
# 其他 location 配置...
}
}
4.标准化,团队协作更高效
RESTful 有统一的设计规范(如资源用名词、URL 层级表示资源关系、用 HTTP 状态码表示请求结果),团队内所有人按同一标准设计 API:
- 避免 "一人一个风格"(比如有人用
/getUser,有人用/user/query); - 便于接口文档自动化(如 Swagger 可直接基于 RESTful API 生成文档),降低团队协作成本。