You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React+Redux项目RxJS Ajax错误处理及Jest 404测试问题

解决React+Redux+RxJS场景下的404响应处理与Jest测试问题

看起来你在React+Redux+RxJS的项目里遇到了两个头疼的问题:RxJS Ajax没法正确处理404响应,同时写不出对应的Jest测试用例。我来帮你一步步拆解解决!

一、先搞定RxJS Ajax的404错误处理问题

首先得明确:RxJS的ajax操作符默认会把所有4xx/5xx状态码的响应都当成错误抛出,这就是你没法正常处理404的核心原因。我们需要修改请求配置,让RxJS把404视为“正常响应”,而不是错误流。

调整RxJS Ajax请求配置

你可以通过statusCode选项指定哪些状态码算成功,再配合responseType确保正确获取text/html内容:

import { ajax } from 'rxjs/ajax';
import { map, catchError } from 'rxjs/operators';
import { of } from 'rxjs';

export const fetchResource = () => {
  return ajax({
    url: '/your-target-resource',
    responseType: 'text', // 明确指定接收text类型响应(适配text/html)
    // 关键配置:告诉RxJS 200和404都属于成功响应,不会触发catchError
    statusCode: {
      200: true,
      404: true
    }
  }).pipe(
    map(response => {
      // 根据状态码分支处理业务逻辑
      if (response.status === 200) {
        return {
          type: 'GET_RESOURCE_SUCCESS',
          payload: response.response // 直接返回text/html内容
        };
      } else if (response.status === 404) {
        // 这里编写404对应的业务逻辑,比如返回特定action
        return {
          type: 'GET_RESOURCE_NOT_FOUND',
          payload: '请求的资源不存在'
        };
      }
    }),
    catchError(error => {
      // 这里处理真正的网络错误(比如断网、跨域、500等)
      return of({
        type: 'GET_RESOURCE_FAILURE',
        payload: error.message
      });
    })
  );
};

二、编写覆盖404场景的Jest测试用例

接下来我们用Jest+RxJS测试调度器+Nock(模拟HTTP请求)来写测试,确保每个分支都被覆盖。

第一步:安装必要依赖(如果还没装)

npm install --save-dev jest rxjs/testing nock

第二步:编写测试用例

import { TestScheduler } from 'rxjs/testing';
import { fetchResource } from './path-to-your-action-file';
import nock from 'nock';

describe('fetchResource Action', () => {
  let testScheduler;

  // 每次测试前初始化RxJS测试调度器,同步处理异步流
  beforeEach(() => {
    testScheduler = new TestScheduler((actual, expected) => {
      expect(actual).toEqual(expected);
    });
  });

  // 测试后清理Nock的所有模拟
  afterEach(() => {
    nock.cleanAll();
  });

  // 测试200成功场景
  it('dispatches GET_RESOURCE_SUCCESS when resource returns 200', () => {
    // 模拟后端返回200和text/html内容
    nock('http://your-app-domain.com')
      .get('/your-target-resource')
      .reply(200, '<div>Hello from resource</div>', { 'Content-Type': 'text/html' });

    testScheduler.run(({ expectObservable }) => {
      const expectedAction = {
        type: 'GET_RESOURCE_SUCCESS',
        payload: '<div>Hello from resource</div>'
      };

      const action$ = fetchResource();
      // 断言流会发出一个action然后完成
      expectObservable(action$).toBe('(a|)', { a: expectedAction });
    });
  });

  // 测试404场景
  it('dispatches GET_RESOURCE_NOT_FOUND when resource returns 404', () => {
    // 模拟后端返回404
    nock('http://your-app-domain.com')
      .get('/your-target-resource')
      .reply(404, '', { 'Content-Type': 'text/html' });

    testScheduler.run(({ expectObservable }) => {
      const expectedAction = {
        type: 'GET_RESOURCE_NOT_FOUND',
        payload: '请求的资源不存在'
      };

      const action$ = fetchResource();
      expectObservable(action$).toBe('(a|)', { a: expectedAction });
    });
  });

  // 测试网络错误场景
  it('dispatches GET_RESOURCE_FAILURE on network error', () => {
    // 模拟网络错误
    nock('http://your-app-domain.com')
      .get('/your-target-resource')
      .replyWithError('Failed to connect');

    testScheduler.run(({ expectObservable }) => {
      const expectedAction = {
        type: 'GET_RESOURCE_FAILURE',
        payload: 'Failed to connect'
      };

      const action$ = fetchResource();
      expectObservable(action$).toBe('(a|)', { a: expectedAction });
    });
  });
});

测试注意点:

  • 使用TestScheduler可以把异步的RxJS流变成同步测试,避免时序问题
  • nock用来精准模拟HTTP响应,不用依赖真实后端就能测试各种状态码
  • 一定要覆盖200、404、网络错误三个核心场景,确保逻辑无死角

三、Redux Reducer中补充404逻辑

最后别忘了在Reducer里处理新增的GET_RESOURCE_NOT_FOUND action,更新状态:

const initialState = {
  content: '初始默认内容',
  error: null,
  isResourceNotFound: false
};

export const resourceReducer = (state = initialState, action) => {
  switch (action.type) {
    case 'GET_RESOURCE_SUCCESS':
      return {
        ...state,
        content: action.payload,
        error: null,
        isResourceNotFound: false
      };
    case 'GET_RESOURCE_NOT_FOUND':
      return {
        ...state,
        content: '资源不存在的提示文案', // 或者保留初始内容,根据业务需求调整
        error: action.payload,
        isResourceNotFound: true
      };
    case 'GET_RESOURCE_FAILURE':
      return {
        ...state,
        error: action.payload,
        isResourceNotFound: false
      };
    default:
      return state;
  }
};

这样一套操作下来,你就能正确处理404响应,同时拥有覆盖全面的Jest测试用例了!

内容的提问来源于stack exchange,提问作者user

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 08:07:01