RESTful API 学习笔记

RESTful API 学习笔记

RESTful 介绍

REST 只是软件设计风格,不是强制标准,所以网上有大量最佳实践、设计指南,但是不存在官方强制设计标准。

为什么使用 RESTful

早期 Web 项目大多是前后端耦合(PHP、JSP)。 随着移动互联网发展,客户端多样化:Web网页、iOS、Android;还有各类开放平台(微信、微博开放平台),需要一套统一接口,给多端客户端提供数据服务,RESTful 就是为此而生。

REST:Representational State Transfer,表述性状态转移。是一套基于HTTP协议的网络应用设计风格。

核心思想:
– URL(URI)使用名词,用来定位资源
– HTTP动词描述对资源的操作(增删改查),不要把动作写在URL路径里。

HTTP 5个常用动词

动词 作用 对应CRUD 说明
GET 获取资源 Read 查询,不会修改服务器数据
POST 新增资源 Create 创建新资源
DELETE 删除资源 Delete 删除指定资源
PUT 全量更新资源 Update 传递完整对象,缺失字段会被清空
PATCH 局部更新资源 Update 只传需要修改的字段,只更新部分属性,PUT的补充

PUT 与 PATCH 的区别

  1. PUT:要求传递完整资源对象,如果缺少字段,理论后端要把缺失字段清空;适合完整替换资源。
  2. PATCH:只传要修改的少量字段,后端只更新传入的属性,不会触碰其他字段;适合局部修改。

幂等性

HTTP1.1定义:多次执行完全相同请求,对服务器产生的副作用和执行一次完全一样,就是幂等。

动词 是否幂等 说明
GET ✅幂等 查询,不会改变数据,调用多少次结果副作用都一样
DELETE ✅幂等 删除id=1,调用1次和调用N次,最终效果都是id=1不存在
PUT ✅幂等 全量替换资源,多次请求最终资源状态一致
PATCH ❌非幂等 比如数量 += 331,多次调用会重复累加,结果不一样
POST ❌非幂等 多次调用会创建多条新数据

面试常考:PUT是幂等;PATCH、POST不是幂等。

URI设计规范(重点)

URI用来定位资源(名词),URI里面不能出现动词;操作交给HTTP Method。

❌错误(URL里面带动词)

错误写法 问题
GET /api/getDogs url出现get查询动作
POST /api/addDogs url出现add新增动作
POST /api/editDogs url出现edit修改动作
GET /api/deleteDogs?id=2 url出现delete删除动作

✅正确写法(名词+http动词表达动作)

请求方式 URL 含义
GET /api/dogs 获取全部狗狗列表
POST /api/dogs 新增一条狗狗
PUT /api/dogs/1 全量更新id=1的狗狗
DELETE /api/dogs/1 删除id=1的狗狗

学生资源示例

请求方式 URL 业务含义
GET /api/students 获取全部学生列表
GET /api/students/1 获取id=1学生详情
POST /api/students 新增学生
DELETE /api/students/1 删除id=1学生
PUT /api/students/1 全量更新id=1学生信息

同一个URL,不同HTTP请求方式,映射后端不同接口方法。

充分利用HTTP协议特征

REST API 不只是把HTTP当作单纯传输通道,要充分利用HTTP协议本身能力:

  1. 看URI(名词):知道访问什么资源(定位)
  2. 看HTTP Method:知道要做什么操作(动作)
  3. 看HTTP Status状态码:知道请求执行结果
  4. 返回数据格式:主流使用JSON,也可支持XML等格式

常见HTTP状态码

状态码 含义 场景
200 OK 请求成功 GET查询、成功更新
201 Created 创建成功 POST新增资源成功
204 No Content 无返回内容 DELETE删除成功
400 Bad Request 客户端参数错误 参数格式错误、校验失败
401 Unauthorized 未认证 未登录、token失效
403 Forbidden 权限不足 登录成功但是没有访问该资源权限
404 Not Found 资源不存在 url或者id对应的资源找不到
500 Internal Server Error 服务器内部异常 代码报错、数据库异常

业务交互三种结果:

  1. 成功:2xx
  2. 客户端出错:4xx(参数错误、没登录、没权限、资源不存在)
  3. 服务端出错:5xx(后端代码、数据库异常)

实际开发中,除了返回http状态码,响应体内部一般自定义业务码、message提示,方便前端解析业务错误。

SpringBoot代码实现RESTful接口

Controller说明

  • @RestController:组合注解,@Controller + @ResponseBody,返回JSON数据。
  • @GetMapping:等价@RequestMapping(method = RequestMethod.GET)
  • @PostMapping:对应POST新增
  • @PutMapping:对应PUT全量更新
  • @DeleteMapping:对应DELETE删除
  • @PathVariable:获取url路径上的变量 /students/{id}
  • @RequestBody:读取请求体JSON,接收前端提交的JSON对象。

注意:浏览器表单只支持GET、POST;PUT / DELETE 一般使用Postman、Apifox等接口测试工具测试。

Controller完整示例

import org.springframework.web.bind.annotation.*;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.List;

@RestController
@RequestMapping("/api/students")
public class StudentRestController {

    @Autowired
    private IStudentService studentService;

    /**
     * GET /api/students 查询全部学生
     */
    @GetMapping
    public Result selectAll() {
        List<Student> list = studentService.list();
        return Result.ok(list);
    }

    /**
     * GET /api/students/{id} 根据id查询单个学生
     */
    @GetMapping("/{id}")
    public Result selectById(@PathVariable("id") Integer id) {
        Student student = studentService.getById(id);
        return Result.ok(student);
    }

    /**
     * POST /api/students 新增学生
     * 请求体JSON接收对象 @RequestBody
     */
    @PostMapping
    public Result add(@RequestBody Student student) {
        studentService.save(student);
        return Result.ok("添加成功");
    }

    /**
     * DELETE /api/students/{id} 删除学生
     */
    @DeleteMapping("/{id}")
    public Result deleteById(@PathVariable("id") Integer id) {
        studentService.removeById(id);
        return Result.ok("删除成功");
    }

    /**
     * PUT /api/students/{id} 全量更新学生
     */
    @PutMapping("/{id}")
    public Result update(@PathVariable Integer id, @RequestBody Student student) {
        student.setId(id);
        studentService.updateById(student);
        return Result.ok("更新成功");
    }

    /**
     * PATCH /api/students/{id} 局部更新(只更新部分字段)
     */
    @PatchMapping("/{id}")
    public Result patchUpdate(@PathVariable Integer id, @RequestBody Student student) {
        student.setId(id);
        studentService.updateById(student);
        return Result.ok("局部更新成功");
    }
}

vue中的api为user/${id}

统一返回结果 Result工具类(前后端分离通用)

import lombok.Data;

@Data
public class Result {
    private Integer code; //业务码 200成功,500失败
    private String msg;
    private Object data;

    public static Result ok(Object data){
        Result r = new Result();
        r.setCode(200);
        r.setMsg("操作成功");
        r.setData(data);
        return r;
    }

    public static Result fail(String msg){
        Result r = new Result();
        r.setCode(500);
        r.setMsg(msg);
        return r;
    }
}

实际开发常见问题

  1. 浏览器表单不支持PUT、DELETE、PATCH请求

前端Vue/axios可以直接发送;传统form表单需要配置过滤器HiddenHttpMethodFilter。

  1. REST不是教条,复杂业务可以变通
  • 登录、导出、批量操作等业务,很难单纯用名词+http动词表达,可以使用POST,不必硬套REST。
  • 业界很多项目是REST风格 + RPC风格混合。
  1. 查询过滤、分页、排序

不要写在路径中,用url查询参数。 示例: GET /api/students?page=1&size=10&name=张三&sort=age,desc

  1. 版本控制

两种方案:

  • 方式1:url携带版本号:/api/v1/students(简单直观,项目常用)
  • 方式2:http请求头携带版本号。

面试简答

  1. 什么是RESTful?

REST是表述性状态转移,是一套API设计风格,不是标准;URL使用名词定位资源,HTTP动词(GET/POST/PUT/DELETE/PATCH)表达增删改查操作,充分利用HTTP状态码。

  1. PUT 和 PATCH区别?

PUT是全量更新,需要完整对象;PATCH局部更新,只传修改字段。PUT幂等,PATCH非幂等。

  1. 什么是幂等性?

多次相同请求,对服务器产生的副作用和一次请求一样;GET、PUT、DELETE幂等,POST、PATCH非幂等。

  1. URI为什么不能写动词?

URI负责定位资源,动作交给HTTP动词;如果URL写getUser、addUser就违背REST面向资源的设计思想。

上一篇
下一篇