playEdu自定义接口需要满足的格式

二次开发playEdu时,自定义API接口前台react接收报错

奇怪的是,报错中已包含了正确的返回值

怀疑是返回值格式不符合react要求,找到react中定义接口请求参数的代码:src\api\internal\httpClient.ts

TypeScript 复制代码
import axios, { Axios, AxiosResponse } from "axios";
import { message } from "antd";
import { getToken, clearToken } from "../../utils/index";

const GoLogin = () => {
  clearToken();
  window.location.href = "/login";
};

const GoError = (code: number) => {
  // window.location.href = "/error?code=" + code;
};

export class HttpClient {
  axios: Axios;

  constructor(url: string) {
    this.axios = axios.create({
      baseURL: url,
      timeout: 15000,
      withCredentials: false,
      headers: {
        Accept: "application/json",
      },
    });

    //拦截器注册
    this.axios.interceptors.request.use(
      (config) => {
        const token = getToken();
        token && (config.headers.Authorization = "Bearer " + token);
        return config;
      },
      (err) => {
        return Promise.reject(err);
      }
    );

    this.axios.interceptors.response.use(
      (response: AxiosResponse) => {
        let code = response.data.code; //业务返回代码
        let msg = response.data.msg; //错误消息

        if (code === 0) {
          return Promise.resolve(response);
        } else if (code === 404) {
          message.error(msg);
          // 跳转到404页面
          GoError(404);
        } else if (code === 403) {
          message.error(msg);
          // 跳转到无权限页面
          GoError(403);
        } else if (code === 429) {
          message.error(msg);
          // 跳转到429页面
          GoError(429);
        } else if (code === 500) {
          message.error(msg);
          // 跳转到500异常页面
          GoError(500);
        } else {
          GoError(code);
          message.error(msg);
        }
        return Promise.reject(response);
      },
      // 当http的状态码非0
      (error) => {
        let status = error.response.status;
        if (status === 401) {
          message.error("请重新登录");
          GoLogin();
        } else if (status === 404) {
          // 跳转到404页面
          GoError(404);
        } else if (status === 403) {
          // 跳转到无权限页面
          GoError(403);
        } else if (status === 429) {
          // 跳转到429页面
          GoError(429);
        } else if (status === 500) {
          // 跳转到500异常页面
          GoError(500);
        } else {
          GoError(status);
        }
        return Promise.reject(error.response);
      }
    );
  }

  get(url: string, params: object) {
    return new Promise((resolve, reject) => {
      this.axios
        .get(url, {
          params: params,
        })
        .then((res) => {
          resolve(res.data);
        })
        .catch((err) => {
          reject(err.data);
        });
    });
  }

  destroy(url: string) {
    return new Promise((resolve, reject) => {
      this.axios
        .delete(url)
        .then((res) => {
          resolve(res.data);
        })
        .catch((err) => {
          reject(err.data);
        });
    });
  }

  post(url: string, params: object) {
    return new Promise((resolve, reject) => {
      this.axios
        .post(url, params)
        .then((res) => {
          resolve(res.data);
        })
        .catch((err) => {
          reject(err.data);
        });
    });
  }

  put(url: string, params: object) {
    return new Promise((resolve, reject) => {
      this.axios
        .put(url, params)
        .then((res) => {
          resolve(res.data);
        })
        .catch((err) => {
          reject(err.data);
        });
    });
  }

  request(config: object) {
    return new Promise((resolve, reject) => {
      this.axios
        .request(config)
        .then((res) => {
          resolve(res.data);
        })
        .catch((err) => {
          reject(err.data);
        });
    });
  }
}

const APP_URL = import.meta.env.VITE_APP_URL || "";

const client = new HttpClient(APP_URL);

export default client;

虽然我的判断正确,但是我肉眼没有找到具体代码行的证据,绕了几个弯子,在代码中加入debugger单步执行也没有找到原因。

这个过程中我了解了vscode中前台单步调试方法,在需要调试的位置加入一行debugger; 谷歌浏览器访问开发页面,当谷歌执行到debugger;代码就会暂停执行,等待用户调试。

把上述代码交给deepseek,得到答案:

问题分析

在你的拦截器代码中:

typescript

复制代码
this.axios.interceptors.response.use(
  (response: AxiosResponse) => {
    let code = response.data.code; //业务返回代码
    let msg = response.data.msg; //错误消息

    if (code === 0) {
      return Promise.resolve(response);  // ✅ 只有 code === 0 才成功
    } else {
      // 其他所有情况都进入 reject
      return Promise.reject(response);   // ❌ 这就是问题所在!
    }
  }
);

问题根源

  1. 你的接口返回的业务码不是 0

  2. 即使 HTTP 状态码是 200,只要业务码 code !== 0,拦截器就会 Promise.reject(response)

  3. 这导致正确的数据进入了错误处理流程

这个问题是因为java编写的自定义后台api接口返回值格式不规范:

java 复制代码
@BackendPermission(slug = BPermissionConstant.USER_LEARN)
@GetMapping("/progress")
@Log(title = "学员-学习任务完成度", businessType = BusinessTypeConstant.GET)
public ResponseEntity<List<StudentProgressDTO>> getAllStudentProgress() {
    List<StudentProgressDTO> progressList = progressService.getAllStudentProgress();
    return ResponseEntity.ok(progressList);
}

按照规范正确的写法:

java 复制代码
@BackendPermission(slug = BPermissionConstant.USER_LEARN)
@GetMapping("/progress")
@Log(title = "学员-学习任务完成度", businessType = BusinessTypeConstant.GET)
public JsonResponse getAllStudentProgress() {
    List<StudentProgressDTO> progressList = progressService.getAllStudentProgress();
    return JsonResponse.data(progressList);
}

以下是返回值格式定义:

java 复制代码
package xyz.playedu.common.types;

import lombok.Data;

@Data
public class JsonResponse {

    private Integer code;
    private String msg;
    private Object data;

    public JsonResponse(Integer code, String msg, Object data) {
        this.code = code;
        this.msg = msg;
        this.data = data;
    }
相关推荐
i***22071 小时前
SpringBoot返回文件让前端下载的几种方式
前端·spring boot·后端
古韵1 小时前
深入alova3服务端能力:分布式BFF层到API网关的最佳实践
javascript·redis·node.js
技术钱1 小时前
react可视化标尺@scena/react-ruler使用
前端·react.js·前端框架
m0_740043731 小时前
JavaScript
开发语言·javascript·ecmascript
●VON1 小时前
Flutter for OpenHarmony前置知识《Flutter 状态管理入门实战:使用 Provider 构建计数器应用》
前端·学习·flutter·华为·openharmony
艾小码1 小时前
Vue开发三年,我才发现依赖注入的TypeScript正确打开方式
前端·javascript·vue.js
土豆12508 小时前
React-Draggable 快速上手指南
react.js
veneno9 小时前
大量异步并发请求控制并发解决方案
前端