jeecgboot/JeecgBoot · error · Error

sys.api.apiRequestFailed

Error message

sys.api.apiRequestFailed

What it means

This throw lives in the Axios transformRequestHook (the response interceptor). After stripping the native response, it expects res.data to be truthy. If the HTTP response body is empty or null (e.g. a 204 No Content, an empty 200, or a proxy returning nothing), data is falsy and it throws the generic i18n key 'sys.api.apiRequestFailed'. This is the 'no return value at all' branch, distinct from the later non-success-code branch (error 10).

Source

Thrown at jeecgboot-vue3/src/utils/http/axios/index.ts:50

   */
  transformRequestHook: (res: AxiosResponse<Result>, options: RequestOptions) => {
    const { t } = useI18n();
    const { isTransformResponse, isReturnNativeResponse } = options;
    // 是否返回原生响应头 比如:需要获取响应头时使用该属性
    if (isReturnNativeResponse) {
      return res;
    }
    // 不进行任何处理,直接返回
    // 用于页面代码可能需要直接获取code,data,message这些信息时开启
    if (!isTransformResponse) {
      return res.data;
    }
    // 错误的时候返回

    const { data } = res;
    if (!data) {
      // return '[HTTP] Request has no return value';
      throw new Error(t('sys.api.apiRequestFailed'));
    }
    //  这里 code,result,message为 后台统一的字段,需要在 types.ts内修改为项目自己的接口返回格式
    const { code, result, message, success } = data;
    // 这里逻辑可以根据项目进行修改
    const hasSuccess = data && Reflect.has(data, 'code') && (code === ResultEnum.SUCCESS || code === 200);
    if (hasSuccess) {
      if (success && message && options.successMessageMode === 'success') {
        //信息成功提示
        createMessage.success(message);
      }
      return result;
    }

    // 在此处根据自己项目的实际情况对不同的code执行不同的操作
    // 如果不希望中断当前请求,请return数据,否则直接抛出异常即可
    let timeoutMsg = '';
    switch (code) {
      case ResultEnum.TIMEOUT:

View on GitHub (pinned to 96fb33f5ec)

Solutions

  1. For endpoints that legitimately return no body, call defHttp with { isTransformResponse: false } so the raw response passes through.
  2. Ensure the backend always returns a JSON envelope { code, result, message } even for empty results.
  3. Check the network tab for the actual response body — confirm the gateway isn't stripping it.
  4. If using mocks, return a proper Result-shaped object, not undefined.

Example fix

// before — default transform expects a body
defHttp.get({ url: '/api/acknowledge' }); // 204 -> throws

// after — bypass transform for no-body endpoints
defHttp.get({ url: '/api/acknowledge' }, { isTransformResponse: false });
Defensive patterns

Strategy: validation

Validate before calling

// For endpoints that may return no body, bypass the transform
await defHttp.get(
  { url: '/api/no-content' },
  { isTransformResponse: false }
);

Try / catch

try {
  const data = await defHttp.get({ url: '/api/x' });
} catch (e) {
  // empty-body or non-success; check e.message for the i18n key
  if (e.message === t('sys.api.apiRequestFailed')) { /* empty body */ }
}

Prevention

When it happens

Trigger: Backend returns an empty body with HTTP 200; a server/proxy strips the body; a streaming endpoint closes before writing; a mock returns undefined; the response is a 204 No Content but isTransformResponse is true (the default). The throw only occurs when isTransformResponse is true (default) and isReturnNativeResponse is false.

Common situations: Calling an endpoint that legitimately returns no body (DELETE, health-check, no-content acknowledgements) through the default defHttp config; misconfigured nginx/gateway dropping the body; backend exception handlers returning ResponseEntity with no body; mock setup returning {} from the mock adapter but the interceptor seeing null.

Related errors


AI-assisted analysis of jeecgboot/JeecgBoot@96fb33f5ec (2026-08-14). Data as JSON: /api/errors/a2d5e681fb18d43e. Report an issue: GitHub.