软件工程实践——个人技术博客

072303426 王子博 2025-12-23 22:18:12

目录

  • 微信小程序与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连接失败的问题。通过深入研究和实践,我总结出了一套完整的连接测试方法,不仅解决了项目中的实际问题,也提升了自己的技术能力。

技术的难点

  1. 微信小程序的网络请求限制和安全要求(必须使用HTTPS,需要配置合法域名)
  2. 认证token的传递和验证(微信登录流程与后端token管理)
  3. 多环境配置管理(开发环境、测试环境、生产环境的切换)

二、技术详述

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 配置流程

  1. 登录微信公众平台https://mp.weixin.qq.com/
  2. 进入开发设置:开发 → 开发管理 → 开发设置
  3. 配置服务器域名
    • request合法域名:https://your-domain.com
    • uploadFile合法域名:https://your-domain.com
    • downloadFile合法域名:https://your-domain.com

2.4.2 配置注意事项

  • 域名必须使用HTTPS协议
  • 域名必须通过ICP备案
  • 配置后需要等待审核通过(通常几分钟到几小时)
  • 开发环境可以使用"不校验合法域名"选项进行测试

2.5 测试流程图

开始
  ↓
检查后端服务是否启动
  ↓
使用Postman测试后端API
  ↓
检查CORS配置
  ↓
配置微信小程序域名
  ↓
在小程序中测试API调用
  ↓
检查网络请求日志
  ↓
验证响应数据格式
  ↓
测试异常情况处理
  ↓
完成

三、技术使用中遇到的问题和解决过程

问题1:微信小程序网络请求失败

问题描述

在微信小程序中调用后端API时,请求失败,错误信息:

request:fail url not in domain list

问题分析

  1. 原因:微信小程序要求所有网络请求的域名必须在公众平台配置的合法域名列表中
  2. 具体情况:使用http://localhost:8080进行开发测试,但该域名未在合法域名列表中
  3. 影响:无法在真机上测试,只能在开发者工具中使用"不校验合法域名"选项

解决过程

第一步:配置开发环境域名

由于本地开发无法使用HTTPS,我们采用了以下方案:

  1. 方案A:使用内网穿透工具(如ngrok)将本地服务暴露为HTTPS域名
  2. 方案B:在开发者工具中勾选"不校验合法域名、web-view、TLS版本以及HTTPS证书"

第二步:配置生产环境域名

  1. 购买域名并完成ICP备案
  2. 配置SSL证书(使用Let's Encrypt免费证书)
  3. 在微信公众平台配置合法域名:
    • request合法域名:https://your-domain.com
    • uploadFile合法域名:https://your-domain.com
    • downloadFile合法域名:https://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
};

第四步:验证解决

  1. 在开发者工具中测试(不校验合法域名)
  2. 在真机上测试(使用配置的合法域名)
  3. 验证HTTPS连接正常

经验总结

  1. 微信小程序必须使用HTTPS协议
  2. 域名必须通过ICP备案
  3. 开发环境可以使用"不校验合法域名"选项,但生产环境必须配置
  4. 建议使用环境配置管理,方便切换不同环境

问题2:认证token传递问题

问题描述

在需要认证的API调用中,后端返回401未授权错误,但前端已经存储了token。

问题分析

  1. 原因:token未正确传递到后端
  2. 具体情况
    • 前端存储了token:wx.setStorageSync('token', token)
    • 但在请求头中未正确添加Authorization
    • 或者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;
    }
}

经验总结

  1. 使用标准的Bearer Token格式:Authorization: Bearer <token>
  2. 前后端需要统一token的传递方式
  3. 建议使用拦截器统一处理token验证
  4. 添加详细的日志记录,便于排查问题

问题3:响应数据格式不一致

问题描述

前端期望的响应格式与后端返回的格式不一致,导致前端无法正确解析数据。

问题分析

  1. 原因:前后端未统一响应格式规范
  2. 具体情况
    • 后端有时返回{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));
    }
  }
});

经验总结

  1. 前后端需要统一响应格式规范
  2. 建议使用统一的响应类,避免格式不一致
  3. 前端需要统一处理响应,提取data字段
  4. 错误信息要清晰明确,便于排查问题

四、总结

通过这次微信小程序与Spring Boot后端API连接测试的实践,我深入理解了前后端协作的关键技术点:

主要收获

  1. API设计规范:理解了RESTful API设计规范,学会了设计统一的响应格式
  2. 微信小程序开发规范:了解了微信小程序的网络请求限制和安全要求
  3. 测试方法:学会了系统化的测试方法,能够快速定位和解决问题
  4. 问题排查能力:通过解决实际问题,提升了问题分析和解决能力

技术要点总结

  1. 后端配置

    • 正确配置CORS,允许跨域请求
    • 使用统一的响应格式
    • 实现统一的异常处理
    • 添加详细的日志记录
  2. 前端配置

    • 封装统一的网络请求方法
    • 正确处理token传递
    • 统一处理响应格式
    • 添加错误处理和用户提示
  3. 微信小程序配置

    • 配置合法域名(生产环境必须)
    • 使用HTTPS协议
    • 完成ICP备案
  4. 测试方法

    • 使用Postman测试后端API
    • 创建测试接口验证连接
    • 在开发者工具和真机上分别测试
    • 建立测试检查清单

未来改进方向

  1. 自动化测试:建立自动化测试流程,提高测试效率
  2. 性能优化:优化网络请求性能,减少请求次数
  3. 安全性增强:加强token安全,实现token刷新机制
  4. 监控和日志:建立完善的监控和日志系统,及时发现问题

五、参考文献

  1. Spring Boot官方文档

  2. 微信小程序开发文档

  3. RESTful API设计指南

  4. CORS跨域资源共享

  5. HTTP认证:Bearer Token

  6. 《Spring Boot实战》

    • 作者:汪云飞
    • 出版社:电子工业出版社
    • 说明:Spring Boot开发的实战指南,包含API设计和异常处理等内容

博客完成时间:2025年12月23日

...全文
42 回复 打赏 收藏 转发到动态 举报
写回复
用AI写文章
回复
切换为时间正序
请发表友善的回复…
发表回复

114

社区成员

发帖
与我相关
我的任务
社区描述
202501福大-软件工程实践-W班
软件工程团队开发结对编程 高校 福建省·福州市
社区管理员
  • 202501福大-软件工程实践-W班
  • 离离原上羊羊吃大草
  • MiraiZz2
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧