114
社区成员
发帖
与我相关
我的任务
分享在微信小程序开发中,前后端API连接是项目成功的关键环节。本文基于实际项目经验,详细介绍如何建立稳定的微信小程序与Spring Boot后端API连接,包括API设计、微信小程序域名配置、接口测试方法等。通过系统化的测试实践,帮助开发者快速定位和解决连接问题,确保前后端协作顺畅。
学习该技术的原因:在团队项目中,我负责测试和连接工作,经常遇到前后端API连接失败的问题。通过深入研究和实践,我总结出了一套完整的连接测试方法,不仅解决了项目中的实际问题,也提升了自己的技术能力。
技术的难点:
在Spring Boot中,我们遵循RESTful API设计规范,使用标准的HTTP方法和状态码:
@RestController
@RequestMapping("/api/records")
public class RecordController {
// GET请求:获取记录列表
@GetMapping
public ResponseEntity<ApiResponse<List<Record>>> getRecords(
@RequestParam(required = false) String startDate,
@RequestParam(required = false) String endDate) {
// 实现逻辑
}
// POST请求:创建新记录
@PostMapping
public ResponseEntity<ApiResponse<Record>> createRecord(
@RequestBody RecordRequest request) {
// 实现逻辑
}
// PUT请求:更新记录
@PutMapping("/{id}")
public ResponseEntity<ApiResponse<Record>> updateRecord(
@PathVariable Long id,
@RequestBody RecordRequest request) {
// 实现逻辑
}
// DELETE请求:删除记录
@DeleteMapping("/{id}")
public ResponseEntity<ApiResponse<Void>> deleteRecord(@PathVariable Long id) {
// 实现逻辑
}
}
为了便于前端处理,我们设计了统一的API响应格式:
public class ApiResponse<T> {
private int code; // 状态码:200表示成功,其他表示失败
private String message; // 提示信息
private T data; // 数据
private long timestamp; // 时间戳
// 成功响应
public static <T> ApiResponse<T> success(T data) {
ApiResponse<T> response = new ApiResponse<>();
response.setCode(200);
response.setMessage("success");
response.setData(data);
response.setTimestamp(System.currentTimeMillis());
return response;
}
// 失败响应
public static <T> ApiResponse<T> error(int code, String message) {
ApiResponse<T> response = new ApiResponse<>();
response.setCode(code);
response.setMessage(message);
response.setTimestamp(System.currentTimeMillis());
return response;
}
}
使用全局异常处理器统一处理异常:
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(Exception.class)
public ResponseEntity<ApiResponse<Object>> handleException(Exception e) {
logger.error("系统异常", e);
return ResponseEntity.status(500)
.body(ApiResponse.error(500, "系统异常:" + e.getMessage()));
}
@ExceptionHandler(IllegalArgumentException.class)
public ResponseEntity<ApiResponse<Object>> handleIllegalArgument(
IllegalArgumentException e) {
return ResponseEntity.badRequest()
.body(ApiResponse.error(400, "参数错误:" + e.getMessage()));
}
}
在微信小程序中,我们封装了统一的网络请求方法:
// utils/api.js
const BASE_URL = 'https://your-domain.com/api'; // 生产环境
// const BASE_URL = 'http://localhost:8080/api'; // 开发环境
function request(url, method = 'GET', data = null, needAuth = true) {
return new Promise((resolve, reject) => {
// 获取token
const token = wx.getStorageSync('token');
// 构建请求头
const header = {
'Content-Type': 'application/json'
};
if (needAuth && token) {
header['Authorization'] = `Bearer ${token}`;
}
// 显示加载提示
wx.showLoading({
title: '加载中...',
mask: true
});
// 发起请求
wx.request({
url: BASE_URL + url,
method: method,
data: data,
header: header,
success: (res) => {
wx.hideLoading();
if (res.statusCode === 200) {
if (res.data.code === 200) {
resolve(res.data.data);
} else {
// 业务错误
wx.showToast({
title: res.data.message || '请求失败',
icon: 'none'
});
reject(new Error(res.data.message));
}
} else if (res.statusCode === 401) {
// token过期,重新登录
wx.removeStorageSync('token');
wx.navigateTo({
url: '/pages/login/login'
});
reject(new Error('登录已过期'));
} else {
wx.showToast({
title: '网络错误',
icon: 'none'
});
reject(new Error('网络错误'));
}
},
fail: (err) => {
wx.hideLoading();
wx.showToast({
title: '网络请求失败',
icon: 'none'
});
reject(err);
}
});
});
}
// 导出便捷方法
module.exports = {
get: (url, needAuth = true) => request(url, 'GET', null, needAuth),
post: (url, data, needAuth = true) => request(url, 'POST', data, needAuth),
put: (url, data, needAuth = true) => request(url, 'PUT', data, needAuth),
delete: (url, needAuth = true) => request(url, 'DELETE', null, needAuth)
};
// pages/index/index.js
const api = require('../../utils/api');
Page({
data: {
records: []
},
onLoad() {
this.loadRecords();
},
async loadRecords() {
try {
const records = await api.get('/records');
this.setData({ records });
} catch (error) {
console.error('加载记录失败', error);
}
},
async createRecord(recordData) {
try {
const newRecord = await api.post('/records', recordData);
wx.showToast({
title: '创建成功',
icon: 'success'
});
this.loadRecords();
} catch (error) {
console.error('创建记录失败', error);
}
}
});
为了快速验证后端服务状态,我们创建了健康检查接口:
@RestController
@RequestMapping("/api/test")
public class TestController {
@GetMapping("/health")
public ResponseEntity<?> healthCheck() {
Map<String, Object> result = new HashMap<>();
result.put("status", "UP");
result.put("service", "Demo Application");
result.put("timestamp", System.currentTimeMillis());
return ResponseEntity.ok(result);
}
}
测试方法:
# 使用curl测试
curl http://localhost:8080/api/test/health
# 预期响应
{
"status": "UP",
"service": "Demo Application",
"timestamp": 1703123456789
}
创建专门的测试接口,用于验证前后端连接:
@GetMapping("/connection")
public ResponseEntity<?> testConnection(HttpServletRequest request) {
Map<String, Object> result = new HashMap<>();
result.put("status", "success");
result.put("message", "连接成功");
result.put("clientIp", request.getRemoteAddr());
result.put("serverTime", System.currentTimeMillis());
result.put("headers", getRequestHeaders(request));
return ResponseEntity.ok(result);
}
private Map<String, String> getRequestHeaders(HttpServletRequest request) {
Map<String, String> headers = new HashMap<>();
Enumeration<String> headerNames = request.getHeaderNames();
while (headerNames.hasMoreElements()) {
String headerName = headerNames.nextElement();
headers.put(headerName, request.getHeader(headerName));
}
return headers;
}
https://your-domain.comhttps://your-domain.comhttps://your-domain.com开始
↓
检查后端服务是否启动
↓
使用Postman测试后端API
↓
检查CORS配置
↓
配置微信小程序域名
↓
在小程序中测试API调用
↓
检查网络请求日志
↓
验证响应数据格式
↓
测试异常情况处理
↓
完成
在微信小程序中调用后端API时,请求失败,错误信息:
request:fail url not in domain list
http://localhost:8080进行开发测试,但该域名未在合法域名列表中第一步:配置开发环境域名
由于本地开发无法使用HTTPS,我们采用了以下方案:
第二步:配置生产环境域名
https://your-domain.comhttps://your-domain.comhttps://your-domain.com第三步:环境切换配置
在小程序中实现环境切换:
// utils/config.js
const ENV = {
DEV: {
BASE_URL: 'http://localhost:8080/api',
// 开发环境使用本地地址
},
PROD: {
BASE_URL: 'https://your-domain.com/api',
// 生产环境使用配置的域名
}
};
// 根据环境选择配置
const currentEnv = wx.getStorageSync('env') || 'PROD';
const config = ENV[currentEnv];
module.exports = {
BASE_URL: config.BASE_URL
};
第四步:验证解决
在需要认证的API调用中,后端返回401未授权错误,但前端已经存储了token。
wx.setStorageSync('token', token)第一步:检查token存储
// 检查token是否正确存储
const token = wx.getStorageSync('token');
console.log('Token:', token);
第二步:检查请求头设置
发现请求头设置有问题:
// 原始代码(有问题)
header: {
'Content-Type': 'application/json',
'token': token // 错误:应该使用Authorization
}
第三步:修正请求头
// 修改后的代码
const header = {
'Content-Type': 'application/json'
};
if (token) {
header['Authorization'] = `Bearer ${token}`; // 使用Bearer Token格式
}
第四步:后端验证token
检查后端是否正确解析token:
@RestController
public class AuthController {
@GetMapping("/api/user/info")
public ResponseEntity<?> getUserInfo(HttpServletRequest request) {
String authHeader = request.getHeader("Authorization");
if (authHeader != null && authHeader.startsWith("Bearer ")) {
String token = authHeader.substring(7);
// 验证token
// ...
}
return ResponseEntity.ok().build();
}
}
第五步:添加token拦截器
使用Spring拦截器统一处理token验证:
@Component
public class AuthInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler) {
String authHeader = request.getHeader("Authorization");
if (authHeader == null || !authHeader.startsWith("Bearer ")) {
response.setStatus(401);
return false;
}
String token = authHeader.substring(7);
// 验证token有效性
if (!isValidToken(token)) {
response.setStatus(401);
return false;
}
return true;
}
}
Authorization: Bearer <token>前端期望的响应格式与后端返回的格式不一致,导致前端无法正确解析数据。
{code: 200, data: {...}}第一步:统一响应格式
设计统一的响应格式类:
public class ApiResponse<T> {
private int code;
private String message;
private T data;
private long timestamp;
// 构造方法和getter/setter
}
第二步:统一使用响应格式
所有Controller方法都使用统一的响应格式:
@GetMapping("/records")
public ResponseEntity<ApiResponse<List<Record>>> getRecords() {
List<Record> records = recordService.getAllRecords();
return ResponseEntity.ok(ApiResponse.success(records));
}
第三步:前端统一处理
前端统一处理响应格式:
wx.request({
success: (res) => {
if (res.statusCode === 200 && res.data.code === 200) {
// 成功,使用res.data.data
resolve(res.data.data);
} else {
// 失败,显示错误信息
reject(new Error(res.data.message));
}
}
});
通过这次微信小程序与Spring Boot后端API连接测试的实践,我深入理解了前后端协作的关键技术点:
后端配置:
前端配置:
微信小程序配置:
测试方法:
Spring Boot官方文档
微信小程序开发文档
RESTful API设计指南
CORS跨域资源共享
HTTP认证:Bearer Token
《Spring Boot实战》
博客完成时间:2025年12月23日