软件工程实践——个人技术博客
目录
- 微信小程序与Spring Boot后端API连接测试实践
- 一、技术概述
- 二、技术详述
- 2.1 后端API设计
- 2.1.1 RESTful API设计规范
- 2.1.2 统一响应格式
- 2.1.3 异常处理
- 2.2 微信小程序网络请求封装
- 2.2.1 基础请求封装
- 2.2.2 使用示例
- 2.3 测试接口设计
- 2.3.1 健康检查接口
- 2.3.2 API连接测试接口
- 2.4 微信小程序域名配置
- 2.4.1 配置流程
- 2.4.2 配置注意事项
- 2.5 测试流程图
- 三、技术使用中遇到的问题和解决过程
- 问题1:微信小程序网络请求失败
- 问题描述
- 问题分析
- 解决过程
- 经验总结
- 问题2:认证token传递问题
- 问题描述
- 问题分析
- 解决过程
- 经验总结
- 问题3:响应数据格式不一致
- 问题描述
- 问题分析
- 解决过程
- 经验总结
- 四、总结
- 主要收获
- 技术要点总结
- 未来改进方向
- 五、参考文献
微信小程序与Spring Boot后端API连接测试实践
一、技术概述
在微信小程序开发中,前后端API连接是项目成功的关键环节。本文基于实际项目经验,详细介绍如何建立稳定的微信小程序与Spring Boot后端API连接,包括API设计、微信小程序域名配置、接口测试方法等。通过系统化的测试实践,帮助开发者快速定位和解决连接问题,确保前后端协作顺畅。
学习该技术的原因:在团队项目中,我负责测试和连接工作,经常遇到前后端API连接失败的问题。通过深入研究和实践,我总结出了一套完整的连接测试方法,不仅解决了项目中的实际问题,也提升了自己的技术能力。
技术的难点:
- 微信小程序的网络请求限制和安全要求(必须使用HTTPS,需要配置合法域名)
- 认证token的传递和验证(微信登录流程与后端token管理)
- 多环境配置管理(开发环境、测试环境、生产环境的切换)
二、技术详述
2.1 后端API设计
2.1.1 RESTful 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) {
// 实现逻辑
}
}
2.1.2 统一响应格式
为了便于前端处理,我们设计了统一的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;
}
}
2.1.3 异常处理
使用全局异常处理器统一处理异常:
@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()));
}
}
2.2 微信小程序网络请求封装
2.2.1 基础请求封装
在微信小程序中,我们封装了统一的网络请求方法:
// 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)
};
2.2.2 使用示例
// 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);
}
}
});
2.3 测试接口设计
2.3.1 健康检查接口
为了快速验证后端服务状态,我们创建了健康检查接口:
@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
}
2.3.2 API连接测试接口
创建专门的测试接口,用于验证前后端连接:
@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;
}
2.4 微信小程序域名配置
2.4.1 配置流程
- 登录微信公众平台:https://mp.weixin.qq.com/
- 进入开发设置:开发 → 开发管理 → 开发设置
- 配置服务器域名:
- request合法域名:
https://your-domain.com - uploadFile合法域名:
https://your-domain.com - downloadFile合法域名:
https://your-domain.com
- request合法域名:
2.4.2 配置注意事项
- 域名必须使用HTTPS协议
- 域名必须通过ICP备案
- 配置后需要等待审核通过(通常几分钟到几小时)
- 开发环境可以使用"不校验合法域名"选项进行测试
2.5 测试流程图
开始
↓
检查后端服务是否启动
↓
使用Postman测试后端API
↓
检查CORS配置
↓
配置微信小程序域名
↓
在小程序中测试API调用
↓
检查网络请求日志
↓
验证响应数据格式
↓
测试异常情况处理
↓
完成
三、技术使用中遇到的问题和解决过程
问题1:微信小程序网络请求失败
问题描述
在微信小程序中调用后端API时,请求失败,错误信息:
request:fail url not in domain list
问题分析
- 原因:微信小程序要求所有网络请求的域名必须在公众平台配置的合法域名列表中
- 具体情况:使用
http://localhost:8080进行开发测试,但该域名未在合法域名列表中 - 影响:无法在真机上测试,只能在开发者工具中使用"不校验合法域名"选项
解决过程
第一步:配置开发环境域名
由于本地开发无法使用HTTPS,我们采用了以下方案:
- 方案A:使用内网穿透工具(如ngrok)将本地服务暴露为HTTPS域名
- 方案B:在开发者工具中勾选"不校验合法域名、web-view、TLS版本以及HTTPS证书"
第二步:配置生产环境域名
- 购买域名并完成ICP备案
- 配置SSL证书(使用Let's Encrypt免费证书)
- 在微信公众平台配置合法域名:
- request合法域名:
https://your-domain.com - uploadFile合法域名:
https://your-domain.com - downloadFile合法域名:
https://your-domain.com
- request合法域名:
第三步:环境切换配置
在小程序中实现环境切换:
// 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
};
第四步:验证解决
- 在开发者工具中测试(不校验合法域名)
- 在真机上测试(使用配置的合法域名)
- 验证HTTPS连接正常
经验总结
- 微信小程序必须使用HTTPS协议
- 域名必须通过ICP备案
- 开发环境可以使用"不校验合法域名"选项,但生产环境必须配置
- 建议使用环境配置管理,方便切换不同环境
问题2:认证token传递问题
问题描述
在需要认证的API调用中,后端返回401未授权错误,但前端已经存储了token。
问题分析
- 原因:token未正确传递到后端
- 具体情况:
- 前端存储了token:
wx.setStorageSync('token', token) - 但在请求头中未正确添加Authorization
- 或者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;
}
}
经验总结
- 使用标准的Bearer Token格式:
Authorization: Bearer <token> - 前后端需要统一token的传递方式
- 建议使用拦截器统一处理token验证
- 添加详细的日志记录,便于排查问题
问题3:响应数据格式不一致
问题描述
前端期望的响应格式与后端返回的格式不一致,导致前端无法正确解析数据。
问题分析
- 原因:前后端未统一响应格式规范
- 具体情况:
- 后端有时返回
{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));
}
}
});
经验总结
- 前后端需要统一响应格式规范
- 建议使用统一的响应类,避免格式不一致
- 前端需要统一处理响应,提取data字段
- 错误信息要清晰明确,便于排查问题
四、总结
通过这次微信小程序与Spring Boot后端API连接测试的实践,我深入理解了前后端协作的关键技术点:
主要收获
- API设计规范:理解了RESTful API设计规范,学会了设计统一的响应格式
- 微信小程序开发规范:了解了微信小程序的网络请求限制和安全要求
- 测试方法:学会了系统化的测试方法,能够快速定位和解决问题
- 问题排查能力:通过解决实际问题,提升了问题分析和解决能力
技术要点总结
后端配置:
- 正确配置CORS,允许跨域请求
- 使用统一的响应格式
- 实现统一的异常处理
- 添加详细的日志记录
前端配置:
- 封装统一的网络请求方法
- 正确处理token传递
- 统一处理响应格式
- 添加错误处理和用户提示
微信小程序配置:
- 配置合法域名(生产环境必须)
- 使用HTTPS协议
- 完成ICP备案
测试方法:
- 使用Postman测试后端API
- 创建测试接口验证连接
- 在开发者工具和真机上分别测试
- 建立测试检查清单
未来改进方向
- 自动化测试:建立自动化测试流程,提高测试效率
- 性能优化:优化网络请求性能,减少请求次数
- 安全性增强:加强token安全,实现token刷新机制
- 监控和日志:建立完善的监控和日志系统,及时发现问题
五、参考文献
Spring Boot官方文档
- 链接:https://spring.io/projects/spring-boot
- 作者:Spring Team
- 说明:Spring Boot的官方文档,包含CORS配置、异常处理等内容
微信小程序开发文档
- 链接:https://developers.weixin.qq.com/miniprogram/dev/framework/
- 作者:微信团队
- 说明:微信小程序的官方开发文档,包含网络请求、域名配置等内容
RESTful API设计指南
- 链接:https://restfulapi.net/
- 作者:RESTful API Design Team
- 说明:RESTful API设计的最佳实践和规范
CORS跨域资源共享
- 链接:https://developer.mozilla.org/zh-CN/docs/Web/HTTP/CORS
- 作者:MDN Web Docs
- 说明:CORS的详细说明和配置方法
HTTP认证:Bearer Token
- 链接:https://tools.ietf.org/html/rfc6750
- 作者:IETF
- 说明:Bearer Token认证的RFC标准文档
《Spring Boot实战》
- 作者:汪云飞
- 出版社:电子工业出版社
- 说明:Spring Boot开发的实战指南,包含API设计和异常处理等内容
博客完成时间:2025年12月23日
相关推荐
弱电网下光伏并网逆变器序阻抗建模仿真复现扫频法【序阻抗判断稳定性】
内容概要:本文聚焦于弱电网条件下光伏并网逆变器的序阻抗建模与稳定性分析,系统阐述了基于扫频法的阻抗特性仿真与复现方法。通过构建正负序阻抗模型,深入剖析逆变器在弱电网环境中的动态响应特性,结合锁相环、电流环等关键控制环节对系统阻抗的影响机制,采用序阻抗稳定性判据评估多机并网或复杂电网条件下的系统稳定裕度。研究在Simulink平台中实现激励信号注入、频率响应采集与阻抗曲线绘制,为高比例新能源接入背景下并网系统的稳定性分析提供了可靠的仿真手段与理论支撑,尤其适用于SCI级别论文成果的复现与拓展验证。; 适合人群:电力电子、新能源并网技术及相关领域的硕士/博士研究生、科研人员,以及从事光伏逆变器、微电网稳定控制开发的工程技术人员。; 使用场景及目标:①掌握扫频法在电力电子装置阻抗建模中的具体实施流程;②理解并应用基于序阻抗的稳定性判据进行系统稳定边界分析;③用于高水平学术论文(如SCI期刊)中阻抗建模与稳定性分析部分的仿真复现与方法验证; 阅读建议:建议读者结合文中所述方法与提供的参考文献,自主搭建Simulink仿真模型,逐步完成扰动信号设计、数据采集、傅里叶分析及阻抗拟合全过程,深入探究控制参数变化对系统阻抗特性和稳定性的具体影响,强化理论与实践的融合能力。
三相并网逆变器虚拟阻抗+统一有源阻尼策略SVPWM+SPWM调制仿真
内容概要:本文档系统性地介绍了三相并网逆变器的核心控制技术及其在复杂电网环境下的仿真应用,重点涵盖虚拟阻抗与统一有源阻尼策略在SVPWM和SPWM调制方式下的实现方法,旨在提升逆变器的稳定性与电能质量。内容包括无功功率扰动孤岛检测、中点电位平衡控制、低电压穿越(LVRT)、模型预测控制(MPC)、正负序分离、电网前馈控制等关键技术,并扩展至风储联合调频、微电网下垂控制、虚拟同步发电机(VSG)、构网型逆变器等多种典型电力系统应用场景。所有技术均配有基于Simulink/Matlab平台的完整仿真模型、参考文献及说明文档,强调理论分析与仿真实践的深度融合,突出科研中“借力”与创新思维的重要性。; 适合人群:电气工程、自动化、新能源等相关专业的研究生、科研人员及从事电力电子与可再生能源系统开发的工程师;具备MATLAB/Simulink仿真基础和电力系统专业知识的技术人员。; 使用场景及目标:①开展三相并网逆变器控制策略的研究与优化设计;②复现高水平学术论文中的控制算法;③完成毕业课题、科研项目或工程仿真验证;④掌握虚拟阻抗、有源阻尼、SVPWM/SPWM调制、MPC、VSG等核心技术的建模与实现方法;⑤支撑微电网、构网型变流器等前沿方向的科研攻关。; 阅读建议:建议按照资源目录结构化学习,优先选择与自身研究方向契合的内容模块,结合提供的仿真模型、参考文献和说明材料进行实操演练,注重从理论推导到仿真实现的全过程理解,充分利用共享网盘资源深化技术掌握,提升科研效率与创新能力。
chromedriver-win32-159.0.8133.0(Canary).zip
chromedriver-win32-159.0.8133.0(Canary).zip
计算机“101计划”《人工智能引论》教学大纲+课件+实训案例
计算机“101计划”《人工智能引论》教学大纲+课件+实训案例
语音输入法离线语音输入转文字工具2.0支持双档本地识别模型,中英混说精准转写,纯离线运行保护隐私,让打字更高效.zip
大家好,我是大飞哥。日常打字时,频繁切换输入法、断网无法语音转写、或担心语音数据被传至云端,是许多办公族和内容创作者的共同痛点。这款离线语音输入工具 ,正是为此量身打造的 Windows 桌面语音辅助利器。它的核心使命就是按住快捷键说话,松开文字自动上屏,全程本地离线识别,让您在任何可输入文字的窗口内都能实现高效、私密的语音输入,彻底告别网络依赖与隐私焦虑。 在核心功能上,软件内置了两档本地语音识别模型,通过主界面下拉框即可随时切换。默认的“离线·标准”模式响应极快,支持中英混说且自带标点,非常适合日常聊天与文档撰写;而“离线·精准”模式则对纯中文、方言口音及长段落口述的识别准确度更高。更贴心的是,它具备实时预览与一键取消机制,说话过程中若发现说错,按下 Esc 即可取消,一个字都不会误输入;若目标窗口不支持直接写入,文字会自动存入剪贴板,方便您按 Ctrl+V 粘贴,确保每次发声都不白费。 这款工具在具体场景中的表现十分亮眼。对于办公白领,在填写表格、撰写邮件或使用微信、QQ 沟通时,无需频繁切换窗口,按住右键说话即可快速完成信息录入;对于程序员与文字工作者,在代码编辑器或文档中口述注释与段落,能显著提升创作效率;对于经常出差的商务人士,在飞机、高铁等断网环境下,它依然能稳定工作,不经过任何服务器,真正做到了“说了什么只有自己知道”,私密性极佳。 使用体验方面,软件将极简操作贯彻到底。解压后双击 大飞哥语音输入,右下角托盘出现蓝色话筒图标即代表准备就绪。用户只需将光标点进目标输入框,按住右 Alt说话,说完松开,文字便会自动写入。主界面提供了设置快捷键与开机自动启动选项,方便用户按习惯自定义组合键;关闭主窗口并不会退出程序,而是缩至托盘持续待命,彻底退出只需右键托盘或点击主界面按钮,逻辑清晰,零门槛上手。


