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接口统一控制器注解
// 组合注解 = @Controller + @ResponseBody,直接返回JSON数据@RestController@RequestMapping("/api/user")publicclassUserRestController{}3.1 @PathVariable 路径参数(URL路径传参)
适用场景:查询单个资源、删除、修改(RESTful标准传参),参数拼接在URL路径中
请求示例:GET /api/user/1001
/** * 根据ID查询单个用户 * @param id 用户ID(路径参数) * @return 用户信息 */@GetMapping("/{id}")publicResultgetUserById(@PathVariableLongid){returnResult.success("查询成功","用户ID:"+id);}进阶用法:多路径参数、参数别名、必填控制
// 多路径参数 + 别名映射 + 非必填@GetMapping("/{userId}/role/{roleId}")publicResultgetUserRole(@PathVariable("userId")Longuid,@PathVariable(required=false)LongroleId){returnResult.success("多参数查询成功","用户ID:"+uid+",角色ID:"+roleId);}3.2 @RequestParam 查询参数(URL问号传参)
适用场景:列表查询、条件筛选、分页参数,参数拼接在URL?后
请求示例:GET /api/user/list?name=张三&page=1&size=10
/** * 用户条件分页查询 * @param name 用户名(非必填) * @param page 页码(默认1) * @param size 每页条数(默认10) * @return 分页数据 */@GetMapping("/list")publicResultgetUserList(@RequestParam(value="name",required=false,defaultValue="")Stringname,@RequestParam(defaultValue="1")Integerpage,@RequestParam(defaultValue="10")Integersize){Stringres=String.format("筛选用户:%s,页码:%d,条数:%d",name,page,size);returnResult.success("分页查询成功",res);}核心参数说明:
value:前端参数名与后端形参名不一致时做映射
required:是否必填,默认true
defaultValue:参数为空时默认值
3.3 @RequestBody JSON实体参数(POST/PUT核心)
适用场景:新增、修改接口,前端传递JSON格式请求体,最常用的传参方式
注意:GET请求不支持@RequestBody,仅POST/PUT/PATCH可用
第一步:创建实体接收类
importlombok.Data;@DatapublicclassUserDTO{// 用户名privateStringusername;// 手机号privateStringphone;// 年龄privateIntegerage;}第二步:编写新增接口
/** * 新增用户(JSON请求体传参) * @param userDTO 用户信息 * @return 新增结果 */@PostMappingpublicResultaddUser(@RequestBodyUserDTOuserDTO){returnResult.success("新增用户成功",userDTO);}常见报错:415 Unsupported Media Type,原因:前端未设置Content-Type: application/json
3.4 @RequestHeader 请求头参数
适用场景:获取Token、请求设备信息、自定义请求头等
/** * 获取请求头中的Token * @param token 登录令牌 * @return 校验结果 */@GetMapping("/token")publicResultgetToken(@RequestHeader("Authorization")Stringtoken){returnResult.success("获取Token成功","令牌:"+token);}3.5 普通表单参数(无注解接收)
适用场景:form表单提交,Content-Type: application/x-www-form-urlencoded
无需任何注解,直接通过形参接收,参数名与前端一致即可
@PostMapping("/form")publicResultformSubmit(Stringusername,Stringpassword){returnResult.success("表单提交成功","账号:"+username+",密码:"+password);}3.6 统一响应结果封装(规范REST返回值)
为满足RESTful接口统一返回规范,封装通用Result工具类,所有接口统一返回格式:
importlombok.Data;@DatapublicclassResult<T>{// 响应码:200成功 500失败privateIntegercode;// 响应信息privateStringmsg;// 响应数据privateTdata;// 成功响应publicstatic<T>Result<T>success(Stringmsg,Tdata){Result<T>result=newResult<>();result.setCode(200);result.setMsg(msg);result.setData(data);returnresult;}// 失败响应publicstatic<T>Result<T>error(Stringmsg){Result<T>result=newResult<>();result.setCode(500);result.setMsg(msg);returnresult;}}四、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
importorg.springframework.context.annotation.Configuration;importorg.springframework.web.servlet.config.annotation.CorsRegistry;importorg.springframework.web.servlet.config.annotation.WebMvcConfigurer;/** * 全局跨域配置(方案一:WebMvc配置) * 生产推荐:精准配置域名,禁止直接使用* */@ConfigurationpublicclassCorsConfigimplementsWebMvcConfigurer{@OverridepublicvoidaddCorsMappings(CorsRegistryregistry){// 匹配所有接口路径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、高并发项目
核心优势:过滤器层级最高,可解决拦截器、权限框架导致的跨域失效问题
importorg.springframework.context.annotation.Bean;importorg.springframework.context.annotation.Configuration;importorg.springframework.web.cors.CorsConfiguration;importorg.springframework.web.cors.UrlBasedCorsConfigurationSource;importorg.springframework.web.filter.CorsFilter;importjava.util.Arrays;/** * 全局跨域配置(方案二:CorsFilter过滤器) * 优先级高于WebMvc配置,适合整合权限框架的项目 */@ConfigurationpublicclassCorsFilterConfig{@BeanpublicCorsFiltercorsFilter(){CorsConfigurationconfig=newCorsConfiguration();// 允许的前端域名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);// 匹配所有接口UrlBasedCorsConfigurationSourcesource=newUrlBasedCorsConfigurationSource();source.registerCorsConfiguration("/**",config);returnnewCorsFilter(source);}}5.3 方案三:yml配置文件极简配置(快速开发)
适用场景:本地开发、快速测试,不推荐生产使用(灵活性差)
在application.yml中直接添加配置:
# 全局跨域配置spring:web:cors:allowed-origins:http://localhost:3000allowed-methods:GET,POST,PUT,DELETE,OPTIONSallowed-headers:*allow-credentials:truemax-age:36005.4 局部跨域配置(了解即可)
通过@CrossOrigin注解,作用于类或方法,仅对当前接口生效:
@RestController@RequestMapping("/api/user")@CrossOrigin(origins="http://localhost:3000")publicclassUserRestController{// 所有接口自动跨域}六、生产环境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干货!有问题评论区交流,秒回!