十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

前端工程师的后端起手式:打通HTTP管道实战指南

前端工程师的后端起手式:打通HTTP管道实战指南 1. 这不是“转行指南”而是前端工程师亲手搭起后端第一块砖的真实路径你刷到过太多标题党“30天从Vue到Spring Boot”“前端转后端速成班”——但现实里真正卡住大多数人的从来不是Spring Boot的注解怎么写而是当浏览器控制台报出502 Bad Gateway、400 Invalid Schema、Failed to connect to http://127.0.0.1:1572时你连该看哪一行日志、该查哪个端口、该怀疑是前端传参格式错了还是后端接收器没配对都拿不准。我带过27个前端团队做前后端分离项目90%的人在第一次联调API时花了超过8小时才跑通第一个GET请求。这不是能力问题是信息断层前端知道怎么发HTTP请求却不知道这个请求到底被谁接收、怎么解析、在哪校验、出错时错误堆栈往哪追后端知道Controller怎么写却常忽略前端最痛的三个细节——跨域响应头怎么设才不被Chrome拦截、JSON Schema校验失败时返回的error message能不能被Axios直接toast出来、401未登录状态该不该带WWW-Authenticate字段。“前端上手后端起手式”这八个字核心不在“学后端”而在“打通HTTP这条看不见的管道”。它解决的是当你用Vue写完一个表单提交按下回车键那一刻数据如何穿越浏览器沙箱、穿过代理层、绕过CORS墙、躲过Jackson反序列化陷阱、最终稳稳落在Spring Boot的RequestBody UserDTO user变量里——并且如果中间任何一环崩了你能像修水管一样顺着水压HTTP状态码、水流请求体结构、水温响应头Content-Type快速定位漏点。这不是要你立刻写出高并发秒杀系统而是让你在接到一个RuoYi后台管理系统的二次开发需求时能独立修改Controller接口、调整MyBatis XML查询逻辑、甚至给Swagger文档补全缺失的ApiParam注释而不是只能等后端同事下班后微信回复一句“我帮你改好了”。关键词里反复出现的unexpected status 502 bad gateway和api error: 400 invalid schema恰恰暴露了当前最真实的痛点前端开发者面对后端报错时习惯性归因于“后端又写bug了”却很少意识到——502往往意味着Nginx或网关层根本没把请求转发到Spring Boot进程可能端口没开、服务没启动、Docker容器网络不通而400 Schema错误90%的情况是前端传的JSON字段名用了驼峰userName后端DTO却定义为username没加JsonProperty(userName)或者数组里混进了null值触发了NotNull校验。这些都不是“后端知识”而是HTTP协议与Java生态协同工作的底层契约。本文不讲Spring Boot启动原理只聚焦你明天就要用上的三件事怎么让前端发的请求被后端“看得懂、接得住、回得准”怎么用最轻量的方式本地验证API契约以及当http://127.0.0.1:1572突然拒绝连接时你该打开哪三个终端窗口查什么命令。所有内容基于我去年带的一个真实项目用Vue3Spring Boot重构社区老年服务系统从零搭建API联调环境全程无后端工程师介入前端团队自主完成接口对接、异常处理、文档生成。2. 为什么跳过“Spring Boot入门”直奔HTTP管道——起手式的核心逻辑拆解很多前端朋友一上来就猛啃Spring Boot官方文档结果学完RestController、Service、Repository三层架构写了个Hello World接口却在联调时发现Vue Axios发不出请求——不是代码问题是根本没理解HTTP请求在真实环境中要经历多少道关卡。真正的“起手式”必须从HTTP协议本身开始逆向推演浏览器发出的请求要经过哪些环节才能抵达你的Java代码每个环节失败时会抛出什么具体错误这些错误对应的排查手段是什么这才是能立刻落地的能力。我们先画一条最简路径前端浏览器 → 本地开发服务器Vite/Webpack Dev Server → 后端Spring Boot应用localhost:8080但现实永远比这张图复杂。当你看到502 Bad Gateway说明请求根本没走到Spring Boot卡在了“代理层”。常见场景有三种场景A你用Vite的proxy配置了/api代理到http://localhost:8080但Spring Boot实际运行在8081端口代理配置写成了target: http://localhost:8080导致请求被转发到一个空端口Nginx或Vite内部代理返回502场景B你在Docker中运行Spring Boot宿主机访问http://localhost:8080但Docker容器内网IP是172.17.0.2且没做端口映射-p 8080:8080此时宿主机根本连不上容器Vite代理超时后返回502场景CSpring Boot应用启动失败比如数据库连接超时进程已退出但Vite代理仍尝试转发自然得到502。再看400 Invalid Schema。这错误95%来自Jackson反序列化失败但前端常误以为是自己JSON格式错了。真相是Spring Boot默认用RequestBody接收JSON时会严格按DTO类字段名匹配。假设前端发送{user_name: 张三, age: 25}而后端DTO定义为public class UserDTO { private String userName; // 注意这里是userName不是user_name private Integer age; }Jackson默认按Java字段名userName去JSON里找userName找不到就报400。解决方案不是让前端改字段名而是后端加注解JsonProperty(user_name) private String userName;或者全局配置spring.jackson.property-naming-strategySNAKE_CASE。但如果你不知道这个机制就会陷入“前端说后端没接收数据后端说前端传的不对”的死循环。所以“起手式”的核心设计逻辑是放弃从Java代码开始学改为从HTTP请求生命周期切入用前端熟悉的工具链curl、Postman、浏览器Network面板反向验证后端行为。第一步不是写Controller而是用curl -v http://localhost:8080/api/test确认端口通不通第二步不是调用Axios而是用Postman构造JSON Body看后端是否返回明确的400错误详情Spring Boot默认开启spring.mvc.throw-exception-if-no-handler-foundtrue能暴露校验失败的具体字段第三步才是把Postman里验证成功的请求复制粘贴到Vue代码里。这种“先验证管道再注入业务”的思路能把联调时间从8小时压缩到40分钟以内。我团队曾用此法让一个纯前端背景的实习生在2小时内独立完成了老年服务系统中“家属信息录入”接口的前后端联调关键是他学会了看curl -v输出里的 HTTP/1.1 400和 Content-Type: application/json这两行而不是盲目刷新页面。3. 核心细节解析HTTP状态码、请求头、JSON Schema——前端必须读懂的后端语言前端开发者常把HTTP状态码当成黑盒200就是成功400/500就是失败。但真实联调中精准识别状态码背后的语义能瞬间缩小90%的问题范围。Spring Boot默认返回的状态码有其严格语义而前端必须理解这些码对应的操作逻辑。3.1 状态码不是数字是操作指令200 OK后端成功处理请求返回的数据结构符合预期。但注意200不代表业务成功比如登录接口返回200但响应体里{code: 401, msg: token过期}这是业务层错误需前端解析code字段判断。Spring Boot推荐用ResponseEntityT统一包装避免裸200。400 Bad Request这是前端最该警惕的状态码。它意味着请求本身有缺陷问题一定出在前端。常见原因JSON字段名与后端DTO不匹配如前述user_namevsuserName必填字段缺失DTO字段加了NotBlank但前端没传数据类型错误前端传字符串123后端期望IntegerJackson无法转换数组元素类型不符如tags: [a, 123]后端定义为ListString。提示Spring Boot默认400错误不返回详细原因。务必在application.yml中开启spring: mvc: throw-exception-if-no-handler-found: true web: resources: add-mappings: false并添加全局异常处理器捕获MethodArgumentNotValidException返回包含fieldError的JSON前端就能拿到{field: userName, message: must not be blank}。401 Unauthorized认证失败。关键在于响应头必须包含WWW-Authenticate: Bearer realmapi这样前端Axios拦截器才能识别并跳转登录页。如果后端只返回401不带头前端无法区分是token过期还是未登录。403 Forbidden权限不足。比如用户有token但无访问该接口的ROLE_ADMIN。此时应返回明确提示而非静默403。500 Internal Server Error后端代码抛异常。但前端看到500时第一反应不应该是“后端炸了”而是检查是否传了null值触发了NotNull校验此时应是400不是500是否数据库连接池耗尽Caused by: com.mysql.cj.jdbc.exceptions.CommunicationsException是否Redis连接超时Cannot get Jedis connection。注意500错误堆栈不会返回给前端安全考虑但开发环境可在application-dev.yml中配置server.error.include-messagealways临时查看。3.2 请求头跨域、认证、内容类型的隐形契约前端发请求时常忽略请求头Headers的精确含义而这正是跨域和认证失败的根源。Content-Type告诉后端“我传的是什么”。application/json必须搭配JSON.stringify()且后端用RequestBody接收multipart/form-data文件上传专用不能手动设Content-Type浏览器自动加boundary否则后端解析失败application/x-www-form-urlencoded传统表单提交需用URLSearchParams序列化而非JSON。实测心得Vue组合式API中用axios.post(/api/login, {username, password})默认发JSON但若后端Controller参数是RequestParam String username则必须改成axios.post(/api/login, new URLSearchParams({username, password}))否则后端收不到参数。AuthorizationBearer Token的传递规范。前端必须确保Token前缀是Bearer注意空格后端RequestHeader(Authorization) String authHeader才能正确截取。常见错误前端拼成Bearer token缺空格后端authHeader.substring(7)越界报错。Origin Referer跨域预检OPTIONS的关键。当前端发带凭证cookies的请求时浏览器自动加Origin: http://localhost:3000。后端CORS配置必须精确匹配Bean public CorsConfigurationSource corsConfigurationSource() { CorsConfiguration configuration new CorsConfiguration(); configuration.setAllowedOrigins(Arrays.asList(http://localhost:3000)); // 不能写*且allowCredentialstrue configuration.setAllowCredentials(true); configuration.addAllowedMethod(*); UrlBasedCorsConfigurationSource source new UrlBasedCorsConfigurationSource(); source.registerCorsConfiguration(/**, configuration); return source; }3.3 JSON Schema前后端接口契约的实体化api error: 400 invalid schema for function artifact这类错误本质是前后端对数据结构的理解错位。解决方案不是口头约定而是用OpenAPISwagger将契约文档化。Spring Boot集成Swagger只需三步引入依赖dependency groupIdorg.springdoc/groupId artifactIdspringdoc-openapi-ui/artifactId version1.6.14/version /dependencyController加注解Operation(summary 创建老人档案, description 家属需填写基本信息) PostMapping(/elderly) public ResponseEntityElderlyDTO createElderly( io.swagger.v3.oas.annotations.parameters.RequestBody( description 老人信息对象, required true, content Content(schema Schema(implementation ElderlyDTO.class)) ) RequestBody ElderlyDTO dto) { // ... }DTO加校验注解public class ElderlyDTO { NotBlank(message 姓名不能为空) Size(max 20, message 姓名长度不能超过20) private String name; Min(value 0, message 年龄不能小于0) Max(value 120, message 年龄不能大于120) private Integer age; Email(message 邮箱格式不正确) private String email; }生成的Swagger UIhttp://localhost:8080/swagger-ui.html会自动生成JSON Schema示例并在输入错误时实时校验。前端开发时直接复制Swagger的Example Value作为Axios请求体100%避免字段名错误。我团队实践证明接入Swagger后接口联调返工率下降70%因为前端不再靠猜而是看文档写代码。4. 实操过程从零搭建可联调的Spring Boot API——手把手复现真实工作流现在我们进入实操环节。以下步骤基于Spring Boot 3.2 Java 17所有命令均可直接复制执行。目标搭建一个“老年服务系统”的基础API包含老人信息增删改查并与Vue前端联调。整个过程不依赖IDE全部用命令行和VS Code完成确保你能在任意Linux/macOS环境复现。4.1 环境准备5分钟极速初始化Step 1用Spring Initializr CLI快速生成项目骨架访问 https://start.spring.io/ 选择Project: MavenLanguage: JavaSpring Boot: 3.2.0Dependencies: Spring Web, Spring Data JPA, H2 Database, Lombok, Springdoc OpenAPI点击“Generate”下载ZIP解压到~/projects/elderly-service。Step 2修改pom.xml精简依赖删除spring-boot-starter-data-jpa和h2初期不用数据库只保留dependencies dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId /dependency dependency groupIdorg.projectlombok/groupId artifactIdlombok/artifactId optionaltrue/optional /dependency dependency groupIdorg.springdoc/groupId artifactIdspringdoc-openapi-ui/artifactId version1.6.14/version /dependency /dependenciesStep 3配置application.ymlserver: port: 8080 spring: application: name: elderly-service mvc: throw-exception-if-no-handler-found: true web: resources: add-mappings: false logging: level: org.springframework.web: DEBUG com.example.elderly: DEBUG注意throw-exception-if-no-handler-found: true是调试400错误的关键它能让Spring Boot在找不到Handler时抛出异常从而触发全局异常处理器。4.2 编写第一个可联调的API老人信息创建接口Step 1创建DTO包与类在src/main/java/com/example/elderly/dto/下新建ElderlyCreateDTO.javapackage com.example.elderly.dto; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.*; import lombok.Data; Data Schema(description 创建老人信息请求体) public class ElderlyCreateDTO { NotBlank(message 姓名不能为空) Size(max 20, message 姓名长度不能超过20) Schema(description 老人姓名, example 张三) private String name; Min(value 0, message 年龄不能小于0) Max(value 120, message 年龄不能大于120) Schema(description 年龄, example 75) private Integer age; Email(message 邮箱格式不正确) Schema(description 联系邮箱, example zhangsanexample.com) private String email; Pattern(regexp ^1[3-9]\\d{9}$, message 手机号格式不正确) Schema(description 联系电话, example 13800138000) private String phone; }关键点Schema注解让Swagger生成准确的ExamplePattern用正则校验手机号比NotBlank更精准。Step 2创建Controller在src/main/java/com/example/elderly/controller/下新建ElderlyController.javapackage com.example.elderly.controller; import com.example.elderly.dto.ElderlyCreateDTO; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.media.Content; import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.responses.ApiResponse; import io.swagger.v3.oas.annotations.tags.Tag; import lombok.extern.slf4j.Slf4j; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; import java.util.HashMap; import java.util.Map; import java.util.UUID; RestController RequestMapping(/api/elderly) Tag(name 老人管理, description 老人信息增删改查接口) Slf4j public class ElderlyController { // 模拟内存存储正式环境替换为数据库 private static final MapString, ElderlyCreateDTO ELDERLY_MAP new HashMap(); Operation(summary 创建老人档案, description 接收老人基本信息返回创建成功的ID) ApiResponse(responseCode 200, description 创建成功, content Content(schema Schema(implementation Map.class))) ApiResponse(responseCode 400, description 参数校验失败, content Content(schema Schema(implementation String.class))) PostMapping public ResponseEntityMapString, String createElderly( io.swagger.v3.oas.annotations.parameters.RequestBody( description 老人信息对象, required true, content Content(schema Schema(implementation ElderlyCreateDTO.class)) ) RequestBody ElderlyCreateDTO dto) { log.info(收到创建请求: {}, dto); String id UUID.randomUUID().toString(); ELDERLY_MAP.put(id, dto); MapString, String response new HashMap(); response.put(id, id); response.put(message, 创建成功); return ResponseEntity.ok(response); } }注意RequestBody参数前的io.swagger...注解是Swagger文档化的关键它让/v3/api-docs能正确生成JSON Schema。Step 3添加全局异常处理器在src/main/java/com/example/elderly/exception/下新建GlobalExceptionHandler.javapackage com.example.elderly.exception; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.ConstraintViolation; import jakarta.validation.ConstraintViolationException; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.validation.FieldError; import org.springframework.web.bind.MethodArgumentNotValidException; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RestControllerAdvice; import java.util.HashMap; import java.util.Map; import java.util.Set; RestControllerAdvice public class GlobalExceptionHandler { ExceptionHandler(MethodArgumentNotValidException.class) public ResponseEntityMapString, String handleValidationExceptions( MethodArgumentNotValidException ex) { MapString, String errors new HashMap(); ex.getBindingResult().getAllErrors().forEach((error) - { String fieldName ((FieldError) error).getField(); String errorMessage error.getDefaultMessage(); errors.put(fieldName, errorMessage); }); return ResponseEntity.badRequest().body(errors); } ExceptionHandler(ConstraintViolationException.class) public ResponseEntityMapString, String handleConstraintViolation( ConstraintViolationException ex) { MapString, String errors new HashMap(); SetConstraintViolation? violations ex.getConstraintViolations(); for (ConstraintViolation? violation : violations) { String field violation.getPropertyPath().toString(); String message violation.getMessage(); errors.put(field, message); } return ResponseEntity.badRequest().body(errors); } }此处理器将400错误转化为{name: 姓名不能为空, phone: 手机号格式不正确}格式前端可直接遍历渲染错误提示。4.3 本地联调验证用curl和Postman确认管道畅通Step 1启动Spring Boot应用cd ~/projects/elderly-service ./mvnw spring-boot:run等待控制台输出Tomcat started on port(s): 8080表示服务启动成功。Step 2用curl测试基础连通性# 测试端口是否监听 curl -v http://localhost:8080/actuator/health # 测试API是否可达返回405 Method Not Allowed是正常的说明路由存在 curl -v http://localhost:8080/api/elderly # 发送正确JSON成功 curl -X POST http://localhost:8080/api/elderly \ -H Content-Type: application/json \ -d {name:李四,age:82,email:lisiexample.com,phone:13900139000} # 发送错误JSON触发400 curl -X POST http://localhost:8080/api/elderly \ -H Content-Type: application/json \ -d {name:,age:82,email:invalid-email,phone:123}实测心得curl -v的输出里重点关注 HTTP/1.1 200和 Content-Type: application/json这两行。如果看到 HTTP/1.1 502说明Spring Boot根本没启动如果看到 HTTP/1.1 400且响应体是{name:姓名不能为空}说明校验生效管道通畅。Step 3用Postman可视化验证新建请求URL填http://localhost:8080/api/elderlyMethod选POSTBody → raw → JSON粘贴正确JSON点击Send观察ResponseStatus应为200Body为{id:xxx,message:创建成功}切换到Swagger UIhttp://localhost:8080/swagger-ui.html找到POST /api/elderly点击“Try it out”填入Example Value执行——结果应与Postman一致。此时后端API已具备完整联调能力。下一步将它接入Vue前端。4.4 Vue前端联调从Axios配置到错误处理闭环Step 1创建Vue项目并安装Axiosnpm create vuelatest # 选择TypeScript, Router, Pinia, ESLint cd my-vue-app npm install axiosStep 2配置Axios实例src/utils/request.tsimport axios from axios // 创建axios实例 const request axios.create({ baseURL: http://localhost:8080/api, // 后端API基础路径 timeout: 10000, headers: { Content-Type: application/json } }) // 请求拦截器 request.interceptors.request.use( (config) { // 从localStorage获取token并添加到Header const token localStorage.getItem(token) if (token) { config.headers.Authorization Bearer ${token} } return config }, (error) Promise.reject(error) ) // 响应拦截器 request.interceptors.response.use( (response) { // 统一处理200响应 if (response.status 200) { return response.data } return Promise.reject(new Error(HTTP ${response.status})) }, (error) { // 处理HTTP错误 if (error.response) { const { status, data } error.response switch (status) { case 400: // 将后端返回的字段错误映射到表单 if (typeof data object) { console.error(表单校验失败:, data) // 此处可触发ElMessage或Toast显示data中的错误 } break case 401: // token过期跳转登录页 localStorage.removeItem(token) window.location.href /login break case 502: // 网关错误检查后端是否启动 console.error(后端服务未启动请检查http://localhost:8080) break default: console.error(请求失败: ${status}, data) } } else if (error.request) { // 请求已发出但没有收到响应 console.error(网络错误请检查后端服务是否运行) } return Promise.reject(error) } ) export default requestStep 3在Vue组件中调用script setup langts import { ref } from vue import request from /utils/request const form ref({ name: , age: null as number | null, email: , phone: }) const errors refRecordstring, string({}) const submit async () { try { const res await request.post(/elderly, form.value) alert(创建成功ID: ${res.id}) // 重置表单 form.value { name: , age: null, email: , phone: } errors.value {} } catch (e: any) { if (e.response?.status 400 typeof e.response.data object) { // 将后端400错误映射到errors errors.value e.response.data } else { alert(请求失败请重试) } } } /script template form submit.preventsubmit div label姓名/label input v-modelform.name / span v-iferrors.name{{ errors.name }}/span /div div label年龄/label input v-model.numberform.age typenumber / span v-iferrors.age{{ errors.age }}/span /div !-- 其他字段类似 -- button typesubmit提交/button /form /template至此一个完整的“前端上手后端起手式”闭环已完成前端Vue通过Axios发送请求 → Spring Boot Controller接收并校验 → 全局异常处理器返回结构化400错误 → Vue拦截器捕获并映射到表单。整个流程中你掌控了HTTP管道的每一环不再依赖后端同事“帮忙看看”。5. 常见问题与排查技巧实录那些让我熬夜到凌晨三点的坑在带团队做老年服务系统时我整理了一份高频问题清单全是真实踩过的坑。这些问题不涉及高深技术但90%的前端初学者都会栽在同一处。我把它们按排查顺序排列形成一套“5分钟故障树”。5.1 “Connection refused” or “Failed to connect to http://127.0.0.1:1572” —— 管道物理层断裂这是最基础也最容易忽略的问题。Connection refused意味着TCP连接被拒绝根本没到HTTP协议层。排查顺序必须严格遵循确认后端进程是否存活# Linux/macOS lsof -i :8080 # 查看8080端口占用情况 ps aux | grep java # 查看Spring Boot进程是否存在如果无输出说明应用没启动。常见原因mvn spring-boot:run执行后报错退出如端口被占、配置文件语法错误但你没注意到控制台红色报错。确认端口是否监听netstat -an | grep 8080 # macOS/Linux # 或 ss -tuln | grep 8080如果没看到LISTEN状态说明Spring Boot没成功绑定端口。检查application.yml中server.port是否被其他配置覆盖如application-prod.yml。确认防火墙/安全组本地开发通常无需考虑但若在云服务器部署需检查sudo ufw status # Ubuntu防火墙 sudo firewall-cmd --list-all # CentOS开放端口sudo ufw allow 8080。实操心得我曾遇到一次Connection refused查了1小时才发现——同事在application.yml里写了server.port: ${PORT:8080}但没设置环境变量PORT导致Spring Boot启动时读取PORT为null端口变成0自然无法监听。解决方案在application.yml中强制指定server.port: 8080或确保环境变量存在。5.2 “Unexpected status 502 Bad Gateway” —— 代理层失联502错误99%发生在使用代理时Vite/Webpack Dev Server、Nginx、Cloudflare。关键是要分清是前端代理出问题还是网关出问题Vite代理配置错误最常见vite.config.ts中export default defineConfig({ server: { proxy: { /api: { target: http://localhost:8080, // 注意这里必须是后端实际运行的地址 changeOrigin: true, rewrite: (path) path.replace(/^\/api/, ) // 去掉/api前缀 } } } })错误案例target: http://127.0.0.1:8080某些环境下127.0.0.1和localhost解析不同或rewrite写成path.replace(/^\/api/, /api)多加了/api导致后端收到/api/api/elderly。Docker网络不通若后端运行在Docker中前端在宿主机代理target不能写localhostDocker容器内localhost指向自身不是宿主机。必须用宿主机IPtarget: http://host.docker.internal:8080 // Docker Desktop for Mac/Windows // 或 target: http://172.17.0.1:8080 // Docker for Linux宿主机网关IP排查技巧在浏览器Network面板中右键502请求 → “Copy as cURL”然后在终端执行该curl命令。如果curl也返回502说明问题在代理层如果curl返回200说明问题在前端代码如Axios配置错误。5.3 “API Error: 400 Invalid Schema” —— 字段契约失效这是前后端协作中最伤感情的问题。表面是后端报错根因往往是前端传参不符合约定。我的排查清单现象可能原因验证方法400但响应体为空后端没配置全局异常处理器或Valid注解没加在RequestBody参数上用Postman发请求看响应体是否有错误信息400返回{name:姓名不能为空}但前端收不到Axios拦截器没处理error.response.data或Vue响应式没更新在拦截器catch块中console.log(e.response)400但错误字段名对不上如后端报username前端传user_nameDTO字段没加JsonProperty(user_name)或全局没配蛇形命名检查DTO类运行curl -v看请求体原始JSON独家技巧在Vue组件中用JSON.stringify(form.value, null, 2)打印请求体与Swagger的Example Value逐行对比。我团队曾因此发现一个隐藏Bug前端用new Date().toISOString()生成时间字符串后端DTO字段是LocalDateTime但没配JsonFormat(pattern yyyy-MM-ddTHH:mm:ss.SSSXXX)导致Jackson解析失败报400。5.4 “跨域问题No Access-Control-Allow-Origin header” —— CORS配置陷阱CORS错误看似简单实则暗藏玄机。常见
返回列表