一、前言
经过前 7 天的开发,我们已经有了能返回数据的后端接口(Day7 的宠物列表接口)和初始化完成的前端 Uni-App 项目(Day4),今天终于要实现 “前后端数据打通”——用 Uni-App 发送网络请求,把后端的宠物数据渲染到前端页面上。
Uni-App 中发送网络请求,我们会用 Axios(一个轻量的 HTTP 请求库,像 “快递员” 一样帮前端把请求送到后端,再把数据带回来)。为了避免每次请求都写重复代码,我们先封装一个request.js工具文件;同时,前后端分离项目很容易遇到 “跨域问题”(就像不同小区之间的 “通行限制”),今天也会教大家用后端配置彻底解决这个问题。
即使你是第一次用 Axios 也不用慌,我们从 “安装→封装→调用” 一步步来,每段代码都带详细注释,确保你能跟着做出来。
二、今日教学目标
- 掌握 Uni-App 中 Axios 的安装与封装(request.js),避免重复编写请求代码;
- 学会在 Vue 页面中调用后端接口(Day7 的/chongwuxinxi/list),并渲染宠物列表数据;
- 理解跨域问题的原因,能用后端CORSConfig配置解决跨域报错。
三、前置准备
- 已完成 Day7 内容:后端/chongwuxinxi/list接口能正常返回数据(用 Postman 测试通过);
- 已打开 Uni-App 项目(front目录),且 HBuilder X 已安装 “终端” 插件(用于执行 npm 命令);
- 安装 Axios:
-
- 在 HBuilder X 中,右键front项目→选择 “在终端中打开”;
-
- 输入命令npm install axios,按下回车(等待安装完成,项目会新增node_modules文件夹)。
四、代码实现(核心:请求封装 + 调用 + 跨域解决)
1. 第一步:封装 Axios 请求(request.js)
为了方便后续所有接口调用(比如后续的商家接口、订单接口),我们先封装一个request.js,统一配置后端地址、超时时间、请求拦截器等。
(1)创建request.js文件
路径:C:\Users\骆\Downloads\my-pet-custom\mypet\src\main\webapp\front\api\request.js(手动创建api文件夹,用于存放所有请求工具)。
(2)编写封装代码
// 导入安装好的Axios
import axios from 'axios';
// 创建Axios实例:相当于“定制一个专属快递员”,统一配置请求规则
const service = axios.create({
baseURL: 'http://localhost:8080', // 后端项目的基础地址(固定,所有接口都基于这个地址拼接)
timeout: 5000, // 请求超时时间:5秒内没响应就报错(避免一直等)
headers: {
'Content-Type': 'application/json;charset=utf-8' // 请求头:告诉后端数据格式是JSON
}
});
// 请求拦截器:发送请求前的“预处理”(比如后续加登录Token)
service.interceptors.request.use(
(config) => {
// 这里可以加后续需要的Token(比如用户登录后,把Token放在请求头里)
// 示例:config.headers.Authorization = 'Bearer ' + uni.getStorageSync('token');
return config; // 必须返回config,否则请求发不出去
},
(error) => {
// 请求发送失败时的处理(比如网络错误)
console.error('请求发送失败:', error);
return Promise.reject(error);
}
);
// 响应拦截器:收到后端响应后的“预处理”(比如统一处理错误)
service.interceptors.response.use(
(response) => {
// 只返回后端的核心数据(response.data才是后端返回的JSON,去掉外层包装)
return response.data;
},
(error) => {
// 响应失败时的处理(比如接口报错、超时)
console.error('接口响应失败:', error);
// 可以加弹窗提示用户(Uni-App的弹窗API)
uni.showToast({
title: '请求失败,请稍后再试',
icon: 'none',
duration: 2000
});
return Promise.reject(error);
}
);
// 导出封装好的Axios实例,供其他页面调用
export default service;
2. 第二步:在 Vue 页面中调用接口(渲染宠物列表)
我们在 “宠物” Tab 对应的页面(pages/pet/index.vue)中调用接口,把后端返回的宠物数据渲染到页面上。
(1)打开 / 创建 Vue 页面
路径:C:\Users\骆\Downloads\my-pet-custom\mypet\src\main\webapp\front\pages\pet\index.vue(如果没有,新建pet文件夹和index.vue)。
(2)编写页面代码(模板 + 脚本)
<template>
<!-- 页面容器:Uni-App的基础布局标签 -->
<view class="pet-list-container">
<!-- 标题 -->
<view class="page-title">宠物列表</view>
<!-- 宠物列表:用v-for循环渲染每一条宠物数据 -->
<view class="pet-item" v-for="(pet, index) in petList" :key="index">
<!-- 宠物名称 -->
<view class="pet-name">名称:{{ pet.mingcheng }}</view>
<!-- 宠物品种 -->
<view class="pet-breed">品种:{{ pet.pinzhong }}</view>
<!-- 宠物年龄 -->
<view class="pet-age">年龄:{{ pet.nianling }}</view>
</view>
<!-- 空数据提示:如果petList为空,显示“暂无宠物数据” -->
<view class="empty-tip" v-if="petList.length === 0">
暂无宠物数据
</view>
</view>
</template>
<script>
// 导入封装好的request.js(请求工具)
import request from '@/api/request.js';
export default {
// 页面数据:存放宠物列表
data() {
return {
petList: [] // 初始为空数组,接口返回数据后赋值
};
},
// 页面生命周期:onLoad在页面加载时执行(只执行一次)
onLoad() {
// 调用“获取宠物列表”的方法
this.getPetList();
},
// 页面方法:存放自定义逻辑
methods: {
// 获取宠物列表:调用后端接口
getPetList() {
// 用封装的request发送GET请求,地址是“后端基础地址 + /chongwuxinxi/list”
request.get('/chongwuxinxi/list')
.then((res) => {
// 请求成功:res是后端返回的核心数据(响应拦截器已处理)
console.log('获取宠物列表成功:', res);
// 把后端返回的数据赋值给petList,页面会自动渲染
this.petList = res;
})
.catch((err) => {
// 请求失败:捕获错误(比如跨域、接口报错)
console.error('获取宠物列表失败:', err);
});
}
}
};
</script>
<style scoped>
/* 页面样式:用scoped确保样式只作用于当前页面 */
.pet-list-container {
padding: 20rpx; /* Uni-App推荐用rpx做单位,适配不同屏幕 */
}
.page-title {
font-size: 32rpx;
font-weight: bold;
margin-bottom: 30rpx;
}
.pet-item {
background-color: #fff;
padding: 20rpx;
border-radius: 16rpx;
margin-bottom: 20rpx;
box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05); /* 轻微阴影,更美观 */
}
.pet-name, .pet-breed, .pet-age {
font-size: 28rpx;
margin-bottom: 10rpx;
color: #333;
}
.empty-tip {
font-size: 28rpx;
color: #999;
text-align: center;
margin-top: 100rpx;
}
</style>
3. 第三步:解决跨域问题(后端配置CORSConfig)
如果直接运行前端页面,浏览器控制台会报 “Access to XMLHttpRequest at 'http://localhost:8080/chongwuxinxi/list' from origin 'http://localhost:8081' has been blocked by CORS policy”(跨域错误),原因是前端(比如 H5 端口 8081)和后端(端口 8080)“域名 / 端口不同”,浏览器出于安全限制拦截了请求。
解决方法:在后端添加 CORS 配置,允许前端跨域请求。
(1)创建CORSConfig.java文件
路径:src/main/java/com/config/CORSConfig.java(后端项目的 config 包下)。
(2)编写跨域配置代码
package com.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* 跨域配置类:解决前后端分离的跨域问题
*/
@Configuration // 标记为Spring配置类,项目启动时自动加载
public class CORSConfig implements WebMvcConfigurer {
/**
* 配置跨域规则
*/
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**") // 对所有接口生效(/**表示所有路径)
.allowedOrigins("*") // 允许所有前端来源(开发环境用*,生产环境可指定具体域名,如"http://www.mypet.com")
.allowedMethods("GET", "POST", "PUT", "DELETE") // 允许的请求方法(GET查询、POST提交等)
.allowedHeaders("*") // 允许所有请求头(比如Token、Content-Type)
.maxAge(3600L); // 预检请求的有效期(1小时,避免频繁发送预检请求)
}
}
五、效果验证
1. 启动后端项目
- 打开 IDEA,重启后端项目(确保CORSConfig生效);
- 用 Postman 再次测试/chongwuxinxi/list接口,确认能正常返回数据。
2. 运行 Uni-App 前端项目(H5 端)
- 在 HBuilder X 中,右键front项目→选择 “运行→运行到浏览器→Chrome”;
- 浏览器自动打开前端页面,切换到 “宠物” Tab(底部 TabBar):
-
- 若后端有数据,页面会显示每条宠物的 “名称、品种、年龄”;
-
- 若后端无数据,页面显示 “暂无宠物数据”;
-
- 打开浏览器控制台(F12),在 “Console” 面板能看到 “获取宠物列表成功” 的日志。
3. 小程序端验证(可选)
- 在 HBuilder X 中,右键front项目→选择 “运行→运行到小程序模拟器→微信开发者工具”;
- 微信开发者工具加载完成后,切换到 “宠物” Tab,同样能看到宠物列表数据(跨域配置对小程序也生效)。
六、常见问题与解决方案
| 问题描述 | 可能原因 | 解决方案 |
|---|---|---|
| 浏览器控制台报 “CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource” | 后端未添加CORSConfig配置,或配置未生效 | 1. 确认CORSConfig.java已放在com.config包下;2. 检查类上是否加了@Configuration注解;3. 重启后端项目(配置类需重启生效) |
| 前端报 “Request failed with status code 404” | 1. request.js中的baseURL错误(比如多写了项目名,如http://localhost:8080/mypet);2. 接口路径写错(如/chongwuxi/list少写 “n”) | 1. 确认baseURL是http://localhost:8080(与后端 Tomcat 端口一致);2. 检查接口路径是否与后端@RequestMapping一致(后端是/chongwuxinxi/list,前端不能错) |
| 前端页面无数据,控制台报 “Cannot read property 'data' of undefined” | 1. Axios 请求未进入then,直接进入catch(比如后端接口报错);2. 后端返回数据格式不是数组(比如返回{code:200, data:[]},但响应拦截器没处理) | 1. 查看控制台 “接口响应失败” 的错误日志,定位后端问题;2. 检查request.js的响应拦截器:若后端返回格式是{code:200, data:[]},需修改拦截器为return response.data.data;(取内层 data) |
| HBuilder X 终端执行npm install axios报错 “npm command not found” | HBuilder X 未配置 Node.js 环境(npm 是 Node.js 的包管理工具) | 1. 下载安装 Node.js(官网:nodejs.org/,安装时勾选 “Add to PATH”);2. 重启 HBuilder X,重新打开终端执行命令 |
七、工具类 / 框架特性拓展
1. request.js封装的好处
- 避免重复代码:如果有 10 个接口,不用每个接口都写axios.create、超时时间、错误处理;
- 统一维护:后续需要加登录 Token、修改后端地址,只需改request.js一处,所有接口都生效;
- 错误统一处理:接口报错时,不用每个页面都写弹窗提示,响应拦截器统一弹 “请求失败”。
2. 跨域问题的本质与生产环境配置
- 本质:浏览器的 “同源策略”(协议、域名、端口三者必须一致,否则拦截请求),比如前端http://localhost:8081(端口 8081)和后端http://localhost:8080(端口 8080)属于 “不同端口”,触发跨域;
- 生产环境配置:开发环境用allowedOrigins("*")方便,但生产环境为了安全,需指定具体前端域名,比如:
.allowedOrigins("http://www.mypet.com", "https://mypet-app.com") // 只允许官网和App的前端域名跨域
八、结语
今天我们成功实现了 “前后端数据打通”—— 你的前端页面能正常显示宠物列表吗?
如果遇到跨域错误、接口 404、数据不渲染等问题,欢迎在评论区分享:
- 浏览器控制台的错误截图(关键部分打码);
- 你的request.js中baseURL配置和接口路径;
我们一起分析问题,确保大家都能搞定 “网络请求” 这个关键步骤!