news 2026/10/19 3:18:07

Java后端项目实战:Servlet+Vue前后端分离外卖平台全流程

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Java后端项目实战:Servlet+Vue前后端分离外卖平台全流程

简介:这份资源是一套前后端分离的饿了么平台后端项目,前端采用 Vue.js,后端基于 Servlet,并通过 AJAX 完成异步数据交互,适合正在学习 Java Web、Vue 基础或前后端分离开发的初学者与课程设计者。内容覆盖用户登录、商品查询、订单处理等典型业务,并涉及 JSON 数据交换、RESTful API、MVC/MVVM 架构、数据库操作及 JWT 安全验证等关键知识点。压缩包共 131 个文件,包含 Java 源码、编译后 class 文件、Vue 前端页面、HTML 页面、CSS/LESS/SCSS 样式、JavaScript 脚本及 XML 配置等,整体 4.15MB,结构小巧便于快速下载与本地部署。目前已有 1435 人学习下载,适合用于理解前后端分离开发流程、Servlet 接口设计与页面交互实现。通过项目源码与配置文件,可直观掌握从工具类编写到登录逻辑、AjaxServlet 响应处理的完整实现思路,是 Java Web 课程设计与入门实战的参考案例。

1. 拿到这份Java后端项目先别急着跑:Servlet+Vue前后端分离到底在练什么

这份Java后端项目写的是“某外卖平台”,打开一看技术栈是Servlet + Vue + AJAX,没有Spring Boot,却把前后端分离的链路完整走了一遍。拿到资源如果直接跑起来,多半会在第一个AJAX请求就卡住:不是端口连不上,就是返回的中文变成问号。它解决的问题很具体:前端页面(Vue)通过异步请求调用后端接口(Servlet),后端以JSON返回商家、菜品、购物车与订单数据,最后组成一个可下单的外卖业务闭环。适合的人群也比较明确——想练Java Web基础、需要一份能写进简历的就业项目、或者正在补Servlet和AJAX之间数据流转经验的同学。整条接口设计和请求流程值得照着敲一遍,新手能跟着跑通,熟手也能翻出不少细节问题。

2. 项目结构拆解:某外卖平台的Servlet后端与Vue前端,五个模块一次理清

2.1 后端包结构:Servlet做Controller,业务分组而不是类爆炸

老式Java Web项目最常见的写法是一个页面配一个Servlet,登录就建LoginServlet,注册就建RegisterServlet,功能多了以后class文件越来越多,改一个业务逻辑要翻四五个Servlet。模拟项目X的做法更收敛:后端按业务分成controller、service、dao、entity、util五个包,controller包下一个业务模块只保留一个Controller,所有接口通过action参数区分,整体目录大概长这样:

project-x/ ├── src/main/java │ ├── com.example.controller │ │ ├── BaseServlet.java │ │ ├── SellerController.java │ │ └── OrderController.java │ ├── com.example.service │ ├── com.example.dao │ ├── com.example.entity │ └── com.example.util ├── src/main/resources │ └── db.properties └── webapp/WEB-INF/web.xml

这个结构里controller负责接收请求,service承载业务判断,dao封装JDBC查询,entity对应数据库表,util放JSON转换、数据库连接和token生成工具。因为没引入Spring框架,对象都是需要哪个就new哪个,这条路虽然不够“优雅”,但每一步依赖关系都看得见,比直接上Spring Boot更容易理解Servlet生命周期以及request、response的作用范围。

从调试角度看,这种结构也比框架项目直观。请求进来之后,在BaseServlet里打断点能看到完整的请求头、参数、session信息;再往下走一步,能看清service和dao之间是怎么传参的。如果直接打开一个Spring Boot项目看Controller,参数绑定、异常处理、JSON序列化全被框架藏起来,新手会以为后端就是“写个方法返回对象”这么简单。

2.2 前端目录规划:Vue页面、Axios封装与路由划分

前端部分由Vue CLI搭建,里面比较重要的是api目录和router目录。api目录下把每个后端接口封装成一个函数,组件里不直接拼URL;router目录负责页面跳转和路由守卫。常规拆分如下:

src/ ├── api/ │ ├── http.js │ ├── seller.js │ ├── order.js │ └── user.js ├── views/ │ ├── Login.vue │ ├── SellerList.vue │ └── Cart.vue ├── router/ └── store/

api抽取的好处是将来后端路径调整时,只需要改api目录里的约定,不用翻遍每个Vue组件。router里加一个登录守卫,没有token就跳回登录页,这种基础登录控制在前端单页应用里非常常见。页面上只关心调用哪个函数、拿到的数据长什么样,不关心接口到底请求了哪个URL,前后端分工就清晰了。

值得注意的是,这个前端项目不依赖任何重型UI框架,页面用原生CSS加组件化写法就能撑起来。这其实是好事:你在调接口的时候不会被Element UI的表单校验逻辑干扰,返回的每一条JSON都能直观地渲染到页面上。

2.3 数据库表设计:商家、菜品、购物车与订单的关联关系

外卖业务的核心表是商家、菜品、购物车和订单,模拟项目X用最直接的外键关系把它们串起来:

表名关键字段作用
t_userid, phone, password用户登录
t_sellerid, name, address, delivery_fee商家信息
t_foodid, seller_id, name, price, pic菜品信息
t_cartid, user_id, food_id, quantity购物车明细
t_orderid, order_no, user_id, total_price, status订单主表

关联关系不复杂:商家一对多菜品,用户和菜品通过购物车表做多对多,用户一对多订单。这样的表结构对练手足够,订单明细表没有拆出来是合理的简化,等把主链路跑通之后再扩展。需要注意t_food里的seller_id就是t_seller的id,前端菜品列表接口拿到的就是商家ID,不需要再join回商家表去查名字,数据量小的时候直接拼一个商家的name字段也行。

建表时还有个细节:t_user里的phone字段建议加唯一索引,用户名密码逻辑经常会把手机号作为登录账号;t_order的status字段用TINYINT,0代表待支付,1代表已完成,不要在数据库里存中文状态,接口返回时再映射就好。

2.4 前后端通信:AJAX请求全流程与JSON响应约定

整个请求流程走的是标准前后端分离链路:

Vue页面触发事件 → Axios发送POST请求 → Tomcat接收后交给Servlet → Servlet调用service查库 → 结果用JSON工具类转成字符串 → response输出JSON → Axios响应拦截器解析 → Vue页面刷新数据。

后端返回的JSON格式在项目里是统一的,类似:

{ "code": 200, "message": "OK", "data": { "sellerId": 3, "sellerName": "某湘菜馆", "deliveryFee": 3.0 } }

code为200约定为业务成功,非200时前端统一弹出message里的错误描述,业务数据放在data里。这个约定看似简单,但省去了每个接口单独商量返回结构的麻烦,前端响应拦截器只判断一次code字段就够了。

通信格式上还有个小规矩必须约定好:请求参数怎么传。项目里绝大多数接口用POST,参数可以放form表单也可以放JSON body,但同一个项目中只应该选一种。模拟项目X的登录和列表接口用form参数,下单接口用JSON body,类型切换时后端接收方式完全不同,这个细节在第4章会单独讲。

2.5 选型理由:为什么是Servlet而不是Spring Boot

很多人会问,现在企业里都上Spring Boot了,为什么还拿Servlet做后端。我的看法是:这个资源的目的不是炫技,而是把请求进来之后发生的事讲清楚。Spring Boot里Controller接收请求、参数绑定、异常处理和JSON序列化都已经被框架处理掉了,初学者只看到方法返回一个对象,至于HTTP状态码怎么设置、响应编码在哪里生效,完全是黑匣子。Servlet手写时这些步骤全都要自己控制,一次响应设置错误,立刻就能看到后果。

等Servlet版本跑通,再去看Spring Boot的DispatcherServlet,会发现Spring Boot只是把这些事封装得更好,底层原理并没有变。所以这份资源适合作为Java Web入门后的第一个完整项目,而不是替代Spring Boot的学习。建议两条线并行:先用Servlet资源把请求流转练熟,再对照Spring Boot的注解理解封装关系,面试时被问到“一个请求从浏览器到数据库经历了什么”,你可以讲得比框架使用者细好几个层级。

3. 从零初始化到跑通第一个接口:版本组合、Tomcat运行、Vite代理与SQL导入

3.1 环境版本组合:JDK8、Tomcat8.5、MySQL5.7、Node14

这个项目涉及的环境不少,我一般在类似项目上用这一套组合,互相兼容性最好:

组件推荐版本说明
JDK1.8和Tomcat兼容最稳,老项目基本都编译在1.8
Tomcat8.5或9.x支持Servlet 3.1规范与@WebServlet注解
MySQL5.7或8.0建库时注意字符集统一utf8mb4
Node14 LTS或16 LTS配合Vue CLI 4/5使用

为什么不用JDK17?因为项目里用到的部分老依赖在新JDK下会碰到反射访问限制,报错排查起来很消耗耐心,完全没必要在环境上浪费时间。如果你本机装了多个JDK版本,记得在开发工具里把项目SDK和语言级别全部指到1.8,只改一处很容易出现编译版本不一致的诡异问题。

3.2 后端导入与运行配置:war包和Tomcat启动

后端拿到手之后,先检查是不是Maven结构。如果是,直接用开发工具打开根目录的pom.xml,等待依赖下载完成。这里有一个容易漏掉的地方:pom.xml里通常配了Tomcat插件,可以直接通过Maven命令启动,我一般会用插件方式,省去手动下载Tomcat再配置的步骤:

<plugin> <groupId>org.apache.tomcat.maven</groupId> <artifactId>tomcat7-maven-plugin</artifactId> <version>2.2</version> <configuration> <port>8080</port> <path>/</path> <uriEncoding>UTF-8</uriEncoding> </configuration> </plugin>

这个插件的port参数指定后端服务端口,path指定上下文路径。path设成“/”表示直接通过根路径访问接口,如果设成“/project-x”,那么所有接口URL都要多出一层前缀。uriEncoding设成UTF-8,解决POST参数的中文乱码问题。启动命令是mvn tomcat7:run,启动后后端接口地址就是http://localhost:8080/api/xx。

如果你坚持用手动配置Tomcat的方式,也可以把项目打包成war包丢进Tomcat的webapps目录。要注意war包的名字就是访问路径,假设改成“project-x.war”,接口地址就变成http://localhost:8080/project-x/api/xx,前端代理配置要跟着改,不然请求全部404。

3.3 前端代理配置:vue.config.js里跨域开关

前端项目一般在8081端口下运行,后端在8080,浏览器认为这是跨域请求,直接访问会被拦截。开发阶段的解决办法是在vue.config.js里配devServer代理:

module.exports = { devServer: { port: 8081, proxy: { '/api': { target: 'http://localhost:8080', changeOrigin: true } } } };

这段配置的意思是:前端请求中凡是路径以/api开头的,都转发给http://localhost:8080处理。port是前端页面的端口,target是后端服务地址,changeOrigin设为true会把请求头里的Host字段改写成target的域名,后端不会因为来源不同而拒绝请求。

代理只解决开发阶段的跨域。上线时前端要执行npm run build生成静态文件,放进Tomcat的webapps目录和后端同源部署,请求同一个域名同一个端口下就不再跨域。如果你在开发环境直接双击index.html打开页面,代理不生效,接口会404,这个要特别注意。

3.4 数据库初始化和示例数据编写

数据库部分通常会给一个SQL文件,没有的话自己建也行。核心表结构和示例数据长这样:

CREATE TABLE t_seller ( id INT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(50) NOT NULL, address VARCHAR(255), delivery_fee DECIMAL(5,2) DEFAULT 0 ); INSERT INTO t_seller(name, address, delivery_fee) VALUES ('某湘菜馆', '某路12号', 3.00), ('某沙县小吃', '某街88号', 2.00); CREATE TABLE t_food ( id INT PRIMARY KEY AUTO_INCREMENT, seller_id INT NOT NULL, name VARCHAR(50), price DECIMAL(6,2), pic VARCHAR(255) );

执行SQL之前先执行set names utf8mb4;,再注意连接串上的characterEncoding参数,比如jdbc:mysql://localhost:3306/project_x?characterEncoding=utf8。如果数据库、SQL文件、连接串三个地方的字符集不统一,最容易出现的现象是页面显示正常,但通过命令行看数据是乱码。

3.5 启动顺序与第一个AJAX请求验证

我第一次跑这类项目时习惯按下面顺序来,能省下大量排错时间:

  1. 先启动MySQL,确认3306端口能连上,执行一条select 1;验证。
  2. 再启动后端Tomcat,看控制台有没有报错,用浏览器直接访问http://localhost:8080/api/seller/list,如果能返回JSON说明后端正常。
  3. 然后启动前端npm run serve,打开http://localhost:8081,登录页面能显示出来。
  4. 最后打开浏览器开发者工具,切到Network面板,登录后看/api/user/login和/api/seller/list两个请求是否返回200。

按这个顺序,就算前端页面报错也能立刻判断是后端问题还是代理问题。最忌讳一上来就点页面,报错了不知道在哪一层。

4. 核心代码实战:Servlet统一分发、Token登录、Axios封装与下单接口解析

4.1 BaseServlet统一分发:一个Servlet处理一个模块

后端代码里最值得先读的是BaseServlet,它把/api/*的请求全部收口统一处理,后面的业务Controller只需要暴露具体方法:

@WebServlet("/api/*") public class BaseServlet extends HttpServlet { protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException { String uri = req.getRequestURI(); String action = uri.substring(uri.lastIndexOf("/") + 1); resp.setContentType("application/json;charset=UTF-8"); switch (action) { case "login": userService.login(req, resp); break; case "list": sellerService.list(req, resp); break; default: resp.getWriter().write("{\"code\":404,\"message\":\"接口不存在\"}"); } } @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException { doPost(req, resp); } }

这段代码里最关键的是最后的doGet也调用doPost,否则用GET请求访问列表接口时不会进入任何业务逻辑。action参数通过URL最后一段路径提取,/api/user/login取到login,/api/seller/list取到list,这样每个模块的Controller只需要在BaseServlet里登记自己的方法名。参数说明:switch分发是简化写法,方法多了以后可以改成反射调用,但练手阶段switch最直白,不会因为加大反射复杂度导致排查困难。

4.2 登录接口与Token流程:session为什么会被放弃

前后端分离项目里最常出现的问题是“登录状态保不住”,原因是session默认存服务端、依赖Cookie传递sessionId,而前后端分离时Cookie跨域是个大麻烦。模拟项目X的登录接口采用的是token方案:

public void login(HttpServletRequest req, HttpServletResponse resp) throws IOException { String phone = req.getParameter("phone"); String password = req.getParameter("password"); User user = userDao.findByPhone(phone); if (user != null && user.getPassword().equals(password)) { String token = TokenUtil.create(user.getId()); resp.getWriter().write(Result.success(token)); } else { resp.getWriter().write(Result.fail(401, "手机号或密码错误")); } }

登录成功后会生成一个token字符串返回给前端,前端把它存进localStorage,之后每个请求都带着这个token去证明身份。TokenUtil.create里一般会把用户id和一个过期时间戳拼在一起做加密,生成规则不复杂但必须保证服务端能解开。参数说明:这里用的是getParameter方式读取参数,说明前端提交的是form表单;如果前端用JSON body提交,这里会取不到phone,后面4.5小节单独处理。

4.3 商家列表和菜品列表:POST参数与返回格式

列表类接口在项目里占大头,常见接口约定如下:

接口请求方式参数返回内容
/api/seller/listPOST无code+商家数组
/api/food/listPOSTsellerIdcode+菜品数组
/api/cart/infoPOSTuserId购物车明细

为什么列表接口不用GET而用POST?原因有两个:第一,统一走BaseServlet的doPost分发,省去doGet和doPost两套逻辑;第二,避免参数直接出现在URL里,GET方式传参在浏览器历史记录里留下完整地址,容易泄漏。POST参数拿到之后,用JSON工具类转成字符串写回response,例如:

List<Seller> sellers = sellerDao.findAll(); resp.getWriter().write(Result.success(sellers));

Result.success内部把data字段转成JSON字符串,再拼上code和message。到这里你应该能理解为什么后端返回统一结构那么重要——列表接口、详情接口、下单接口各自返回不同数据结构,但最外面那层判断始终是code,前端处理起来很轻松。

4.4 前端Axios封装:baseURL、拦截器与错误处理

前端入口是api目录下的http.js,所有请求都从这里发出,不在组件里直接new Axios:

import axios from 'axios'; const http = axios.create({ baseURL: '/api', timeout: 5000 }); http.interceptors.request.use(config => { const token = localStorage.getItem('token'); if (token) { config.headers.Authorization = 'Bearer ' + token; } return config; }); http.interceptors.response.use( res => { if (res.data.code === 200) { return res.data.data; } return Promise.reject(new Error(res.data.message)); }, err => { if (err.response && err.response.status === 401) { window.location.href = '/login'; } return Promise.reject(err); } );

baseURL设成/api,组件里调用http.post('/seller/list')实际请求路径就是/api/seller/list。请求拦截器负责把token塞进请求头,约定格式为“Bearer ”加token,后端解析时要按这个前缀切割。响应拦截器统一拆包:code为200时只返回data,非200直接抛错,组件里所有接口的成功回调拿到的都是干净的data对象,不需要每个页面都判断一次code。401状态码则强制跳登录页,避免用户停留在失效页面。

4.5 下单接口的JSON body解析:不要再读getParameter

登录和列表接口用的是form参数,下单接口却换成了JSON body提交,这是项目里最容易翻车的地方。前端下单时提交的数据类似:

{ "userId": 1, "items": [ { "foodId": 101, "quantity": 2 } ], "remark": "少放辣" }

后端接收JSON body时,不能再调用req.getParameter("userId"),而是要主动读取请求流的body,再解析成Java对象:

BufferedReader reader = req.getReader(); StringBuilder body = new StringBuilder(); String line; while ((line = reader.readLine()) != null) { body.append(line); } JSONObject obj = JSON.parseObject(body.toString()); JSONArray items = obj.getJSONArray("items");

req.getReader()拿到的是请求体字符流,JSONObject.parseObject把整个JSON字符串转成可操作的对象。参数说明:userId是外层字段,先解析出来;items是数组,遍历后逐条取foodId和quantity,再分别插入订单明细或生成订单主表记录。如果这一步还在用getParameter,拿到的永远是null,而且不会报任何异常,适合作为排查逻辑问题的重点怀疑对象。

5. 避坑与常见问题:跨域拦截、中文乱码、登录态丢失、端口冲突与404

5.1 跨域报错:代理写了但请求仍被浏览器拦截

现象:前端页面打开正常,Network里的请求显示CORS error,控制台提示No 'Access-Control-Allow-Origin' header is present。

原因:最常见的是直接用浏览器地址栏访问了http://localhost:8080/api/xx,而不是通过前端代理访问。地址栏直接访问时没有经过webpack-dev-server代理,浏览器发现8080端口与前端页面的8081端口不同,执行了同源策略拦截。

解决:先确认页面是通过http://localhost:8081打开的,再看Network里的请求URL是不是/api/xx开头。如果坚持前后端分开部署,后端需要加一个CORS过滤器统一放行:

@WebFilter("/*") public class CorsFilter implements Filter { public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletResponse resp = (HttpServletResponse) response; resp.setHeader("Access-Control-Allow-Origin", "http://localhost:8081"); resp.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS"); resp.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization"); chain.doFilter(request, response); } }

这个过滤器不能滥用*通配符,尤其当请求头带Authorization时,通配符会导致某些浏览器直接拒绝。Allow-Headers里必须显式声明Authorization和Content-Type,否则带token的请求还是会被拦。

5.2 中文乱码:JSON返回问号的三个排查点

现象:Postman请求接口返回数据正常,浏览器页面里显示的中文全部变成了???或ç³»,更诡异的是部分接口正常部分接口乱码。

原因:乱码出在三个环节——response输出编码、request参数编码、数据库连接编码。我见过最深的一次是三个地方都没设编码,页面里商家名字全是问号,排查了一整个下午。

解决:response的编码设置必须在调用getWriter()之前执行,顺序反了不生效:

resp.setContentType("application/json;charset=UTF-8"); resp.setCharacterEncoding("UTF-8");

注意第一行设置ContentType时已经带了charset,第二行是保险写法。request参数乱码时,在BaseServlet的doPost开头加一行req.setCharacterEncoding("UTF-8");,确保getParameter读出来的参数是UTF-8。数据库连接串上补characterEncoding=utf8,建库时用DEFAULT CHARSET=utf8mb4。检查顺序从输出端开始,先用Postman确认接口返回是否乱码,再确认页面渲染,最后排查数据库,避免来回折腾。

5.3 登录状态丢失:Session在前后端分离下的局限

现象:登录成功后页面跳转正常,按F5刷新一下又回到登录页,或者某个接口调用时后端报session为null。

原因:项目一部分接口还在用request.getSession(),另一部分已经换成token,两部分互相不认账。Session依赖浏览器自动携带Cookie,跨端口、跨域环境下Cookie传不过去,session在每次刷新时都可能是新的,登录状态自然保不住。

解决:统一改成token方案,登录接口返回token,前端存在localStorage,请求拦截器统一加到Authorization头,后端写一个拦截器或过滤器校验token。校验通过后把用户信息放进request的attribute里,后续接口从attribute取当前用户,不再依赖session。

String auth = req.getHeader("Authorization"); if (auth == null || !auth.startsWith("Bearer ")) { Result.fail(401, "未登录"); return; } String token = auth.substring(7); User user = TokenUtil.parse(token); if (user == null) { Result.fail(401, "登录已过期"); return; } req.setAttribute("currentUser", user);

这里最坑的一点是headername大小写,HTTP头名称不区分大小写,getHeader("Authorization")和getHeader("authorization")都能取到,但如果前端在拦截器里设置时把key写错了,后端看到的就是null。各端两边的key写对,否则反复排查都是浪费时间。

5.4 Tomcat端口被占用与上下文路径对不上

现象:启动后端时报Address already in use: JVM_Bind :8080,或者明明写了@WebServlet("/api/seller/list"),访问却返回404。

原因:端口被占用是8080被本地另一个进程抢占了,换成8088后控制台不报错,但前端代理还指向8080。404的情况则是war包部署时上下文路径带了名字,实际URL多了一层。

解决:改Tomcat端口时,用编辑器打开conf/server.xml,找到<Connector port="8080"改成8088,不能只改一个地方。Maven插件方式则改pom.xml里的port节点。前端代理的target同步改成http://localhost:8088。上下文路径方面,插件方式<path>/</path>表示没有前缀,手动部署时war包叫什么名字,URL上就要带什么前缀,前端baseURL或代理规则要重新写。

5.5 接口404:注解扫描、编译产物和Artifacts配置

现象:代码里明明有@WebServlet("/api/user/login"),启动Tomcat后访问却404,控制台也没有加载这个Servlet的日志。

原因:典型的是web.xml里的metadata-complete="true"导致容器不扫描注解,只能通过web.xml显式声明Servlet;另一种是IDE打war包时没把编译后的class文件打到WEB-INF/classes目录,Servlet类根本没进最终产物。

解决:先看web.xml头部:

<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" metadata-complete="false">

metadata-complete一定是false,才能通过@WebServlet注解注册。然后检查编译输出目录,确认target/classes里有对应的Servlet.class文件。IDE方式启动时还要检查Artifacts里有没有把classes目录加进去,否则代码编译成功但运行环境看不到。判断依据很简单:去看Tomcat部署后的实际目录结构,如果WEB-INF/classes下面没有你的包结构,那就不是代码问题,是打包问题。

6. 验证技巧:统一Result返回结构,用curl快速核对后端接口

6.1 统一返回结构:用code判断成败,前端少一半逻辑

这份资源把所有接口的返回都统一成了Result对象,这个设计值得保留到日常开发里:

public class Result { private int code; private String message; private Object data; public static Result success(Object data) { Result r = new Result(); r.code = 200; r.message = "OK"; r.data = data; return r; } public static Result fail(int code, String msg) { Result r = new Result(); r.code = code; r.message = msg; return r; } }

code只占用200表示成功,401表示登录失效,业务校验失败统一用400。别把业务错误码设计得像HTTP状态码一样复杂,前端只需要判断成功和失败两种状态,失败时把message直接弹出来就好。code含义越少,前端响应拦截器的逻辑就越简单。

6.2 curl验证法:绕过浏览器直接测后端

前后端联调之前,我习惯先用curl把后端接口全部跑一遍,确认后端没问题再开浏览器,避免把跨域、代理、页面渲染问题混在一起排查:

curl -X POST http://localhost:8080/api/seller/list \ -H "Content-Type: application/json;charset=UTF-8" curl -X POST http://localhost:8080/api/user/login \ -d "phone=13800138000&password=123456"

第一条命令验证列表接口返回的JSON结构,第二条验证登录接口的form参数解析。关键参数解释:-X POST指定请求方式,-H设置请求头,-d传请求体。如果返回的是完整JSON而不是404或500,基本可以认定后端服务、数据库、Servlet映射都没问题,剩下的事就是开前端页面验证AJAX链路。

从那以后我每次接手类似的前后端分离资源,都会先跑一圈curl确认后端接口返回,再开前端联调,避免把问题全堆在浏览器里查。这个习惯帮我省掉了大量“前端报错但后端其实没事”的排查时间,希望帮到你。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/19 3:16:56

Flutter工程规范实战:用Claude Code和Codex约束AI写代码

最近我在几个 Flutter 项目里试了用 Claude Code 和 Codex 来写代码&#xff0c;效果确实惊艳&#xff0c;但翻车概率也一点都不低。最典型的情况是&#xff1a;AI 能独立完成一个小功能&#xff0c;却会在你根本没注意到的地方破坏既有约定——混用状态管理方案、跳过异常处理…

作者头像 李华
网站建设 2026/10/19 3:16:33

lt9211D单片机裸机开发代码包详解:从启动文件到外设驱动

简介&#xff1a;lt9211D单片机工程代码面向嵌入式显示驱动与接口转换开发人员&#xff0c;适用于MIPI DSI信号转LVDS显示接口的场景&#xff0c;可解决LCD面板接入、数据格式转换、初始化时序匹配及调试难等问题。压缩包约514KB&#xff0c;共374个文件&#xff0c;以C源码、头…

作者头像 李华
网站建设 2026/10/19 3:16:15

Windows XP 32位系统安装IE8离线包:步骤与故障排查指南

看到IE8-WindowsXP-x86-CHS_23253_BDdl.exe这个文件名&#xff0c;第一反应往往是&#xff1a;这串字符到底是什么意思&#xff1f;其实它就是 Internet Explorer 8 在 Windows XP 32 位简体中文系统下的完整离线安装包。都什么年代了&#xff0c;还有人装 IE8&#xff1f;你别…

作者头像 李华
网站建设 2026/10/19 3:16:10

半实物仿真测试在惯性组合导航中的工程实践与关键问题

1. 为什么半实物仿真测试在惯性组合导航里是绕不开的一环做惯性组合导航的人&#xff0c;大多经历过这样的场景&#xff1a;算法仿真里精度跑得漂漂亮亮&#xff0c;位置误差曲线圆润得像教科书截图&#xff0c;可一旦把程序烧进真实的导航计算机&#xff0c;接上真实的惯性测量…

作者头像 李华
网站建设 2026/10/19 3:16:02

Python沙箱逃逸:eval白名单下的符号注入与类型混淆

1. 这道题为什么让很多人卡在“数学”两个字上&#xff1f;CISCN 2019初赛的Love Math题&#xff0c;标题里带个“Math”&#xff0c;不少参赛者第一反应是翻出数论教材、掏出欧拉函数公式、开始推导模幂周期——结果调了两小时环境&#xff0c;连flag的影子都没见着。我第一次…

作者头像 李华
网站建设 2026/10/19 3:15:56

从easyflask CTF题剖析Flask应用漏洞利用链与防御

1. 从一道CTF题看Flask应用的典型攻击面"easyflask"这个题目名字本身就带着一种微妙的暗示——出题人觉得它简单&#xff0c;但真正上手之后你会发现&#xff0c;它考察的是一条完整的漏洞利用链&#xff0c;从信息泄露到权限绕过再到代码执行&#xff0c;每一步都踩…

作者头像 李华