RESTful API 面试详解

一、RESTful API 是什么?

一句话定义

RESTful API 是一种基于 HTTP 协议的软件架构风格,它使用标准 HTTP 方法(GET、POST、PUT、DELETE 等)对资源进行操作,让 Web 服务的设计更加简洁、统一。

核心原则(REST 六大约束)

  1. 客户端-服务器分离:前后端分离,独立演化

  2. 无状态:每次请求都包含所有必要信息,服务器不保存会话状态

  3. 可缓存:响应必须明确是否可缓存

  4. 统一接口:使用标准 HTTP 方法和状态码

  5. 分层系统:客户端不知道是与服务器还是中间件通信

  6. 按需代码(可选):服务器可返回可执行代码(如 JavaScript)

RESTful 的设计特征

复制代码
# 传统 API(非 RESTful)
GET /getUser?id=1
POST /updateUser
GET /deleteUser?id=1

# RESTful API(资源导向)
GET    /users/1          # 获取用户1
PUT    /users/1          # 更新用户1
DELETE /users/1          # 删除用户1
POST   /users            # 创建新用户

实际示例

复制代码
// RESTful 风格的控制器
@RestController
@RequestMapping("/api/products")
public class ProductController {
    
    // GET    /api/products      - 获取所有产品
    @GetMapping
    public List<Product> getAllProducts() {
        return productService.findAll();
    }
    
    // GET    /api/products/{id} - 获取单个产品
    @GetMapping("/{id}")
    public Product getProduct(@PathVariable Long id) {
        return productService.findById(id);
    }
    
    // POST   /api/products      - 创建产品
    @PostMapping
    public Product createProduct(@RequestBody Product product) {
        return productService.save(product);
    }
    
    // PUT    /api/products/{id} - 更新产品
    @PutMapping("/{id}")
    public Product updateProduct(@PathVariable Long id, 
                                 @RequestBody Product product) {
        return productService.update(id, product);
    }
    
    // DELETE /api/products/{id} - 删除产品
    @DeleteMapping("/{id}")
    public void deleteProduct(@PathVariable Long id) {
        productService.delete(id);
    }
}

二、GET 和 POST 的区别

对比表格

特性 GET POST
语义 获取数据(安全、幂等) 提交数据(不安全、不幂等)
参数位置 URL 查询字符串 请求体(Body)
参数可见性 明文显示在 URL 隐藏在请求体中
数据长度 有限制(URL长度限制) 无限制(理论上)
安全性 较低(参数在URL中) 较高(参数在Body中)
缓存 可被缓存 不可缓存
浏览器历史 保留记录 不保留记录
后退/刷新 无害 会重新提交(浏览器提示)
幂等性 幂等(多次请求结果相同) 不幂等(每次可能产生不同结果)
书签 可收藏为书签 不可收藏

详细解释

1. 语义区别(最重要)
  • GET获取资源,不应改变服务器状态

    复制代码
    GET /api/users/123
    GET /api/products?category=electronics&page=2
  • POST创建新资源,改变服务器状态

    复制代码
    POST /api/users
    Content-Type: application/json
    
    {"name": "张三", "email": "zhangsan@example.com"}
2. 幂等性
  • GET 是幂等的:执行 1 次和 N 次效果相同

    复制代码
    # 无论请求多少次,都不会创建新用户
    GET /api/users/1  ✅ 安全
    GET /api/users/1  ✅ 安全
    GET /api/users/1  ✅ 安全
  • POST 不是幂等的:每次可能产生不同结果

    复制代码
    # 每次请求都会创建新用户
    POST /api/users  → 创建用户A
    POST /api/users  → 创建用户B
    POST /api/users  → 创建用户C
3. 安全性
  • GET 是安全的:不应改变数据(只读)

  • POST 不安全:会改变数据

4. 参数传递
复制代码
# GET - 参数在URL中
GET /api/search?keyword=java&page=1&size=20

# POST - 参数在Body中
POST /api/login
Content-Type: application/x-www-form-urlencoded

username=zhangsan&password=123456

# POST with JSON
POST /api/users
Content-Type: application/json

{
  "name": "张三",
  "age": 25,
  "email": "zhangsan@example.com"
}
5. 缓存机制
复制代码
// GET 请求可以被缓存
@GetMapping("/products/{id}")
@Cacheable(value = "products", key = "#id")  // Spring Cache
public Product getProduct(@PathVariable Long id) {
    return productService.findById(id);
}

// POST 请求不应该被缓存
@PostMapping("/orders")
public Order createOrder(@RequestBody OrderRequest request) {
    return orderService.create(request);  // 每次都执行
}
6. 实际使用场景
复制代码
// ✅ GET 的正确使用场景
@GetMapping("/users")                    // 获取用户列表
@GetMapping("/users/{id}")              // 获取单个用户
@GetMapping("/users/{id}/orders")       // 获取用户的订单
@GetMapping("/search")                  // 搜索(参数少时)

// ✅ POST 的正确使用场景  
@PostMapping("/users")                  // 创建用户
@PostMapping("/login")                  // 用户登录
@PostMapping("/orders")                 // 下订单
@PostMapping("/search")                 // 复杂搜索(参数多时)

三、面试回答模板

问题1:RESTful API 是什么?

标准回答

"RESTful API 是一种基于 HTTP 协议的架构风格,核心思想是把一切视为资源,用统一的接口进行操作。它有六个约束原则,最重要的是无状态和统一接口。"

"具体来说,它用 URL 表示资源,用 HTTP 方法表示操作:GET 获取、POST 创建、PUT 更新、DELETE 删除。比如用户资源:GET /users 获取列表,POST /users 创建用户,GET /users/1 获取用户1,PUT /users/1 更新用户1,DELETE /users/1 删除用户1。"

加分回答

"在我们项目中,RESTful API 带来了三个好处:第一是前后端解耦,前端只需要知道接口规范;第二是可缓存性提升性能;第三是自描述性,看 URL 就知道操作什么资源。"

问题2:GET 和 POST 有什么区别?

标准回答

"GET 和 POST 有五大核心区别:

  1. 语义不同:GET 获取数据,POST 提交数据

  2. 参数位置:GET 在 URL 中,POST 在请求体里

  3. 安全性:GET 是安全的(只读),POST 不安全(会改数据)

  4. 幂等性:GET 是幂等的,POST 不是幂等的

  5. 可缓存性:GET 可缓存,POST 不可缓存"

"实际开发中,获取数据用 GET,创建数据用 POST。敏感数据如密码一定要用 POST,避免在 URL 中暴露。"

场景化回答

"比如电商网站,搜索商品用 GET:/api/products?q=手机&page=1,参数在 URL 中,可以收藏链接。下单用 POST:/api/orders,订单数据在请求体里,避免刷新重复下单。"

问题3:什么时候用 GET?什么时候用 POST?

判断标准

  1. 用 GET

    • 获取数据(搜索、列表、详情)

    • 参数少且不敏感

    • 希望结果可缓存、可收藏

    • 幂等操作(多次执行结果相同)

  2. 用 POST

    • 创建新资源(注册、下单)

    • 参数多或包含敏感信息

    • 改变服务器状态的操作

    • 非幂等操作(每次可能不同)

实际示例

复制代码
# ✅ GET 合适场景
GET /api/articles?category=tech      # 获取文章列表
GET /api/users/123                   # 获取用户信息
GET /api/products/search?q=手机      # 搜索商品

# ✅ POST 合适场景  
POST /api/login                      # 用户登录(密码敏感)
POST /api/orders                     # 创建订单(改变状态)
POST /api/files/upload               # 上传文件(数据量大)
POST /api/payments                   # 支付请求(敏感操作)

四、高级话题(加分项)

1. 其他 HTTP 方法

  • PUT:更新整个资源(幂等)

  • PATCH:部分更新资源(不幂等)

  • DELETE:删除资源(幂等)

  • HEAD:获取响应头

  • OPTIONS:获取支持的 HTTP 方法

2. 幂等性实践

复制代码
// PUT 是幂等的
@PutMapping("/users/{id}")
public User updateUser(@PathVariable Long id, @RequestBody User user) {
    // 无论调用多少次,结果都一样
    return userService.update(id, user);
}

// PATCH 可能不幂等
@PatchMapping("/users/{id}/balance")
public User addBalance(@PathVariable Long id, @RequestParam BigDecimal amount) {
    // 每次调用余额增加,不幂等
    return userService.addBalance(id, amount);
}

3. RESTful 最佳实践

  • 使用复数名词:/users而不是 /user

  • 使用嵌套资源表示关系:/users/1/orders

  • 使用合适的状态码:200 OK、201 Created、404 Not Found

  • 版本控制:/api/v1/users或 Header 中指定版本

  • 过滤、分页、排序:/users?active=true&page=2&size=20&sort=name,desc

一句话总结RESTful 是用 URL 定位资源,用 HTTP 方法描述操作;GET 是安全的只读操作,POST 是创建资源的非安全操作。

相关推荐
吴巴格2 小时前
springboot引用其他中间件,如何确定版本
spring boot·后端·中间件
IT_陈寒2 小时前
Vue3性能优化实战:5个被低估的API让我减少了40%的代码量
前端·人工智能·后端
鹏程十八少2 小时前
2.Android 3分钟跑通Shadow官方插件化Demo(Maven版):宿主/管理器/插件三工程(实战)
android·前端·面试
IT=>小脑虎2 小时前
AI时代下后端的出路在哪?
人工智能·后端·学习
想摆烂的不会研究的研究生2 小时前
每日八股——Redis(4)
数据库·经验分享·redis·后端·缓存
YYHPLA2 小时前
【无标题】
java·spring boot·后端·缓存
EricLee2 小时前
2025 年终总结 - Agent 元年
前端·人工智能·后端
q***44152 小时前
C++跨平台开发挑战的技术文章大纲编译器与工具链差异
java·后端
熏鱼的小迷弟Liu2 小时前
【消息队列】如何在RabbitMQ中处理消息的重复消费问题?
面试·消息队列·rabbitmq