SpringBoot系列06:RESTful接口开发,请求参数接收、全局跨域CORS完整配置
✅ 系列专栏:SpringBoot零基础进阶实战系列
✅ 适配版本:SpringBoot 3.x / Java 17+
✅ 核心亮点:零基础上手、全覆盖参数接收、三种全局CORS配置、生产级避坑、可直接复用
✅ 阅读收益:彻底掌握RESTful接口规范、所有请求参数接收场景、解决前后端99%跨域问题
一、前言:为什么必须学RESTful与CORS配置?
在前后端分离开发模式中,RESTful API 是目前行业统一的接口设计规范,替代了传统杂乱的接口请求方式,让接口语义清晰、统一规范、易于维护。而CORS跨域问题是前后端联调的高频痛点,90%的接口联调报错都源于跨域配置不当。
本文将从零开始,手把手带大家实现 标准RESTful接口开发 + 全场景请求参数接收 + 生产级全局CORS配置,摒弃零散代码,提供可直接用于项目的完整方案,同时解析底层原理和常见踩坑点。
本文核心知识点清单
-
RESTful API设计规范(四大HTTP方法对应增删改查)
-
SpringBoot五种核心请求参数接收方式(全覆盖业务场景)
-
三种生产级全局CORS跨域配置方案(优先级对比、场景适配)
-
跨域核心原理、常见报错原因与终极解决方案
-
生产环境CORS安全配置避坑指南
二、RESTful API核心设计规范
RESTful(Representational State Transfer)即表述性状态转移,核心思想是用HTTP请求方法定义操作,用URL定义资源,URL只命名资源,不包含操作行为。
2.1 传统接口 vs RESTful接口对比
传统接口风格(不规范):
-
/user/add 新增用户
-
/user/delete 删除用户
-
/user/update 修改用户
-
/user/get 查询用户
RESTful规范风格(标准统一):
| HTTP方法 | 业务操作 | 接口地址 | 说明 |
|---|---|---|---|
| GET | 查询资源 | /api/user | 查询用户列表 |
| GET | 查询单资源 | /api/user/{id} | 根据ID查询单个用户 |
| POST | 新增资源 | /api/user | 新增用户 |
| PUT | 全量修改资源 | /api/user/{id} | 根据ID完整更新用户信息 |
| PATCH | 局部修改资源 | /api/user/{id} | 局部更新用户字段 |
| DELETE | 删除资源 | /api/user/{id} | 根据ID删除用户 |
2.2 RESTful核心约束
-
资源唯一:URL定位唯一资源,名词复数命名(user、order、goods)
-
方法语义化:严格遵循HTTP方法对应增删改查
-
无状态:服务器不存储客户端状态,每次请求独立
-
返回统一格式:统一JSON响应体,包含状态码、信息、数据
三、SpringBoot全场景请求参数接收实战
SpringBoot RESTful接口中,参数接收分为5种核心场景,覆盖所有业务开发需求,下面结合RESTful接口逐一实战演示,所有代码基于SpringBoot3可直接运行。
前置基础:RESTful接口统一控制器注解
java
// 组合注解 = @Controller + @ResponseBody,直接返回JSON数据
@RestController
@RequestMapping("/api/user")
public class UserRestController {
}
3.1 @PathVariable 路径参数(URL路径传参)
适用场景:查询单个资源、删除、修改(RESTful标准传参),参数拼接在URL路径中
请求示例:GET /api/user/1001
java
/**
* 根据ID查询单个用户
* @param id 用户ID(路径参数)
* @return 用户信息
*/
@GetMapping("/{id}")
public Result getUserById(@PathVariable Long id){
return Result.success("查询成功", "用户ID:" + id);
}
进阶用法:多路径参数、参数别名、必填控制
java
// 多路径参数 + 别名映射 + 非必填
@GetMapping("/{userId}/role/{roleId}")
public Result getUserRole(
@PathVariable("userId") Long uid,
@PathVariable(required = false) Long roleId
){
return Result.success("多参数查询成功", "用户ID:"+uid+",角色ID:"+roleId);
}
3.2 @RequestParam 查询参数(URL问号传参)
适用场景:列表查询、条件筛选、分页参数,参数拼接在URL?后
请求示例:GET /api/user/list?name=张三&page=1&size=10
java
/**
* 用户条件分页查询
* @param name 用户名(非必填)
* @param page 页码(默认1)
* @param size 每页条数(默认10)
* @return 分页数据
*/
@GetMapping("/list")
public Result getUserList(
@RequestParam(value = "name", required = false, defaultValue = "") String name,
@RequestParam(defaultValue = "1") Integer page,
@RequestParam(defaultValue = "10") Integer size
){
String res = String.format("筛选用户:%s,页码:%d,条数:%d", name, page, size);
return Result.success("分页查询成功", res);
}
核心参数说明:
-
value:前端参数名与后端形参名不一致时做映射
-
required:是否必填,默认true
-
defaultValue:参数为空时默认值
3.3 @RequestBody JSON实体参数(POST/PUT核心)
适用场景 :新增、修改接口,前端传递JSON格式请求体,最常用的传参方式
注意 :GET请求不支持@RequestBody,仅POST/PUT/PATCH可用
第一步:创建实体接收类
java
import lombok.Data;
@Data
public class UserDTO {
// 用户名
private String username;
// 手机号
private String phone;
// 年龄
private Integer age;
}
第二步:编写新增接口
java
/**
* 新增用户(JSON请求体传参)
* @param userDTO 用户信息
* @return 新增结果
*/
@PostMapping
public Result addUser(@RequestBody UserDTO userDTO){
return Result.success("新增用户成功", userDTO);
}
常见报错:415 Unsupported Media Type,原因:前端未设置Content-Type: application/json
3.4 @RequestHeader 请求头参数
适用场景:获取Token、请求设备信息、自定义请求头等
java
/**
* 获取请求头中的Token
* @param token 登录令牌
* @return 校验结果
*/
@GetMapping("/token")
public Result getToken(@RequestHeader("Authorization") String token){
return Result.success("获取Token成功", "令牌:" + token);
}
3.5 普通表单参数(无注解接收)
适用场景:form表单提交,Content-Type: application/x-www-form-urlencoded
无需任何注解,直接通过形参接收,参数名与前端一致即可
java
@PostMapping("/form")
public Result formSubmit(String username, String password){
return Result.success("表单提交成功", "账号:"+username+",密码:"+password);
}
3.6 统一响应结果封装(规范REST返回值)
为满足RESTful接口统一返回规范,封装通用Result工具类,所有接口统一返回格式:
java
import lombok.Data;
@Data
public class Result<T> {
// 响应码:200成功 500失败
private Integer code;
// 响应信息
private String msg;
// 响应数据
private T data;
// 成功响应
public static <T> Result<T> success(String msg, T data){
Result<T> result = new Result<>();
result.setCode(200);
result.setMsg(msg);
result.setData(data);
return result;
}
// 失败响应
public static <T> Result<T> error(String msg){
Result<T> result = new Result<>();
result.setCode(500);
result.setMsg(msg);
return result;
}
}
四、CORS跨域原理与报错原因
4.1 什么是跨域?
浏览器同源策略限制:协议、域名、端口三者任意一个不同,即为跨域,浏览器会拦截响应,抛出跨域报错。
同源判定规则:http://localhost:8080(后端)与 http://localhost:3000(前端)端口不同 = 跨域
4.2 常见跨域报错
Access to fetch at 'xxx' from origin 'xxx' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
核心原因:后端接口未配置跨域许可,未返回对应的跨域响应头。
五、三种生产级全局CORS配置方案(推荐收藏)
SpringBoot中跨域配置分为局部注解配置 和全局配置 ,局部配置仅对单个接口生效,企业项目统一使用全局配置,下面提供三种主流全局配置方案,适配不同场景。
5.1 方案一:实现WebMvcConfigurer(最推荐、轻量化)
适用场景:绝大多数SpringBoot项目,不影响SpringSecurity、拦截器等配置,优先级适中
核心优势:代码简洁、侵入性低、适配SpringBoot3
java
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* 全局跨域配置(方案一:WebMvc配置)
* 生产推荐:精准配置域名,禁止直接使用*
*/
@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
// 匹配所有接口路径
registry.addMapping("/**")
// 允许跨域的前端域名(生产环境替换为真实前端地址,多个域名用逗号分隔)
.allowedOrigins("http://localhost:3000", "http://127.0.0.1:3000")
// 允许所有请求方法
.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
// 允许所有请求头
.allowedHeaders("*")
// 允许携带Cookie、Token凭证
.allowCredentials(true)
// 预检请求有效期1小时,减少OPTIONS请求次数
.maxAge(3600);
}
}
5.2 方案二:注册CorsFilter过滤器(优先级最高、全局拦截)
适用场景:需要优先执行跨域配置、整合SpringSecurity、高并发项目
核心优势:过滤器层级最高,可解决拦截器、权限框架导致的跨域失效问题
java
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
import java.util.Arrays;
/**
* 全局跨域配置(方案二:CorsFilter过滤器)
* 优先级高于WebMvc配置,适合整合权限框架的项目
*/
@Configuration
public class CorsFilterConfig {
@Bean
public CorsFilter corsFilter() {
CorsConfiguration config = new CorsConfiguration();
// 允许的前端域名
config.setAllowedOrigins(Arrays.asList("http://localhost:3000", "http://127.0.0.1:3000"));
// 允许请求方法
config.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE", "OPTIONS"));
// 允许请求头
config.setAllowedHeaders(Arrays.asList("*"));
// 允许携带凭证
config.setAllowCredentials(true);
// 预检请求缓存时间
config.setMaxAge(3600L);
// 匹配所有接口
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", config);
return new CorsFilter(source);
}
}
5.3 方案三:yml配置文件极简配置(快速开发)
适用场景 :本地开发、快速测试,不推荐生产使用(灵活性差)
在application.yml中直接添加配置:
yaml
# 全局跨域配置
spring:
web:
cors:
allowed-origins: http://localhost:3000
allowed-methods: GET,POST,PUT,DELETE,OPTIONS
allowed-headers: *
allow-credentials: true
max-age: 3600
5.4 局部跨域配置(了解即可)
通过@CrossOrigin注解,作用于类或方法,仅对当前接口生效:
java
@RestController
@RequestMapping("/api/user")
@CrossOrigin(origins = "http://localhost:3000")
public class UserRestController {
// 所有接口自动跨域
}
六、生产环境CORS核心避坑指南(必看)
6.1 禁止使用 allowedOrigins("*")
致命错误:开启allowCredentials(true)时,不能配置*通配符,会直接报错!
原因:浏览器安全机制,允许携带Cookie时,必须指定具体域名,不允许全局开放
生产方案:枚举所有前端合法域名,或通过配置文件动态读取
6.2 OPTIONS预检请求403报错
复杂请求(带Token、自定义请求头)会先发OPTIONS预检请求,必须手动放行OPTIONS方法,否则权限框架会拦截
6.3 配置优先级规则
CorsFilter过滤器 > @CrossOrigin注解 > WebMvc全局配置 > yml配置
项目中只保留一种全局配置,多配置共存会导致跨域失效、冲突报错
6.4 跨域失效常见原因
-
SpringSecurity未放行OPTIONS请求
-
自定义拦截器在跨域过滤器之前执行
-
配置类未加@Configuration注解,未生效
-
前后端端口、域名匹配错误
-
URL拼写格式错误:配置前端跨域域名时,禁止出现多余引号、空格、非法字符(如 `http://127.0.0.1:3000"` 错误格式),URL末尾不能带双引号、逗号等冗余字符,会直接导致跨域配置解析失败、前端请求跨域报错
-
域名协议不匹配:后端配置http协议,前端使用https协议,或反之,引发跨域拦截
-
SpringSecurity未放行OPTIONS请求
-
自定义拦截器在跨域过滤器之前执行
-
配置类未加@Configuration注解,未生效
-
前后端端口、域名匹配错误
七、完整项目测试流程
-
启动SpringBoot项目,端口8080
-
使用Postman/Apifox测试所有RESTful接口
-
启动前端项目(3000端口),调用后端接口,跨域问题彻底解决
-
所有参数接收场景均可正常解析,返回统一JSON格式
八、总结与下期预告
本文总结
-
掌握RESTful标准化接口设计,告别杂乱接口风格
-
吃透5种请求参数接收方式,覆盖100%业务传参场景
-
掌握3种生产级全局CORS配置,解决所有跨域问题
-
熟悉生产环境跨域避坑要点,规避线上故障
下期预告
SpringBoot系列07:全局异常处理+统一返回结果封装,彻底消灭接口杂乱报错
💡 博主寄语
RESTful接口开发和跨域配置是SpringBoot前后端分离的基础必修课,看似简单但极易踩坑。建议大家收藏本文,项目中直接复用配置,规范代码风格,提升开发效率。
码字不易,点赞关注持续更新SpringBoot干货!有问题评论区交流,秒回!