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

如何用React Saga call()调用Node.js POST API?写法是否正确?

React Saga调用REST POST接口的代码正确性验证

我之前用React Saga的call()函数调用基于GraphQL和Apollo Server实现的Node.js API,对应的Saga代码如下:

import {call, put, takeEvery, /* takeLatest */} from 'redux-saga/effects';
import types from './types';
import {
    GET_PLANS_BY_PAGINATION,
    GET_ACTIVE_PLANS_BY_COUNTRY,
    GET_PLAN_DETAIL_BY_ID,
    ADD_PLAN,
    EDIT_PLAN,
    DELETE_PLAN
} from '../../queries/plan'
import client from '../../backend/apolloClient';

// Sagas for Add Plan Starts //
function* addPlanStartHandlerSaga(action)
{
    try
    {
        const {data} = yield call(client.post, {
            mutation        : ADD_PLAN,
            fetchPolicy     : 'network-only',
            variables       : {PlanInput : action.payload}
        })
        if(data?.addPlan?.success === true)
        {
            yield put({type : types.ADD_PLAN_SUCCESS, payload : data?.addPlan?.message})
        }
        else
        {
            yield put({type : types.ADD_PLAN_ERROR, payload : data?.addPlan?.message})
        }
    }
    catch(err)
    {
        yield put({type: types.ADD_PLAN_ERROR, payload: err})
    }
}

export function* addPlanStartWatcherSaga() {
    yield takeEvery(types.ADD_PLAN_START, addPlanStartHandlerSaga)
}
// Sagas for Add Plan Ends //

现在需要用React Saga的call()函数调用REST POST接口,地址为//domain.com/create-stripe-account-and-subscribe,请求头需携带Authorization:Bearer encToken,请求体包含name、email、phoneCode、phoneNumber、role、stripePaymentMethodId、stripePriceId字段。我写了如下代码,请问写法是否正确?

import {call, put, takeEvery, /* takeLatest */} from 'redux-saga/effects';
import types from './types';
import client from '../../backend/apolloClient';

// Sagas for Add Plan Starts //
function* createStripeAccountAndSubscribeStartHandlerSaga(action)
{
    try
    {
        const {data} = yield call(client.POST, {
            url             : '//domain.com/create-stripe-account-and-subscribe',
            fetchPolicy     : 'network-only',
            body            :   {
                                  name                    : action.payload.name,
                                  email                   : action.payload.email,
                                  phoneCode               : action.payload.phoneCode,
                                  phoneNumber             : action.payload.phoneNumber,
                                  role                    : action.payload.role,
                                  stripePaymentMethodId   : action.payload.stripePaymentMethodId,
                                  stripePriceId           : action.payload.stripePriceId
                                }
        })
        if(data?.createStripeAccountAndSubscribe?.success === true)
        {
            yield put({type : types.CREATE_STRIPE_ACCOUNT_AND_SUBSCRIBE_SUCCESS, payload : data?.createStripeAccountAndSubscribe?.message})
        }
        else
        {
            yield put({type : types.CREATE_STRIPE_ACCOUNT_AND_SUBSCRIBE_ERROR, payload : data?.createStripeAccountAndSubscribe?.message})
        }
    }
    catch(err)
    {
        yield put({type: types.CREATE_STRIPE_ACCOUNT_AND_SUBSCRIBE_ERROR, payload: err})
    }
}

export function* createStripeAccountAndSubscribeStartWatcherSaga() {
    yield takeEvery(types.CREATE_STRIPE_ACCOUNT_AND_SUBSCRIBE_START, createStripeAccountAndSubscribeStartHandlerSaga)
}
// Sagas for Add Plan Ends //

代码问题分析

这段写法不正确,存在以下几个关键问题:

  • Apollo Client不支持直接发REST请求:Apollo Client的post方法是专门为GraphQL设计的,不存在用于REST的POST(大写)方法,直接调用会触发方法不存在的错误。
  • 缺少必要请求头:未配置要求的Authorization头,也没设置Content-Type: application/json,后端无法解析请求体或验证身份。
  • 请求体格式错误:REST POST的JSON请求体需要转为字符串,直接传对象会导致后端解析失败。
  • 冗余配置:fetchPolicy是GraphQL的缓存配置,REST请求不需要该参数。
  • 响应处理逻辑错误:REST请求的响应不能直接解构data,需要先将响应转为JSON格式。

修正后的代码示例

方案1:使用原生fetch

import {call, put, takeEvery} from 'redux-saga/effects';
import types from './types';

// 假设encToken从全局状态或环境变量获取
const encToken = 'your-token-here';

function* createStripeAccountAndSubscribeStartHandlerSaga(action) {
    try {
        const response = yield call(fetch, '//domain.com/create-stripe-account-and-subscribe', {
            method: 'POST',
            headers: {
                'Authorization': `Bearer ${encToken}`,
                'Content-Type': 'application/json'
            },
            body: JSON.stringify({
                name: action.payload.name,
                email: action.payload.email,
                phoneCode: action.payload.phoneCode,
                phoneNumber: action.payload.phoneNumber,
                role: action.payload.role,
                stripePaymentMethodId: action.payload.stripePaymentMethodId,
                stripePriceId: action.payload.stripePriceId
            })
        });

        if (!response.ok) {
            throw new Error(`请求失败,状态码:${response.status}`);
        }

        const data = yield call([response, 'json']);
        
        if (data?.createStripeAccountAndSubscribe?.success === true) {
            yield put({
                type: types.CREATE_STRIPE_ACCOUNT_AND_SUBSCRIBE_SUCCESS,
                payload: data?.createStripeAccountAndSubscribe?.message
            });
        } else {
            yield put({
                type: types.CREATE_STRIPE_ACCOUNT_AND_SUBSCRIBE_ERROR,
                payload: data?.createStripeAccountAndSubscribe?.message || '操作失败'
            });
        }
    } catch (err) {
        yield put({
            type: types.CREATE_STRIPE_ACCOUNT_AND_SUBSCRIBE_ERROR,
            payload: err.message || '请求异常'
        });
    }
}

export function* createStripeAccountAndSubscribeStartWatcherSaga() {
    yield takeEvery(types.CREATE_STRIPE_ACCOUNT_AND_SUBSCRIBE_START, createStripeAccountAndSubscribeStartHandlerSaga);
}

方案2:使用axios(需先安装axios)

import {call, put, takeEvery} from 'redux-saga/effects';
import types from './types';
import axios from 'axios';

const encToken = 'your-token-here';

function* createStripeAccountAndSubscribeStartHandlerSaga(action) {
    try {
        const response = yield call(axios.post, '//domain.com/create-stripe-account-and-subscribe', {
            name: action.payload.name,
            email: action.payload.email,
            phoneCode: action.payload.phoneCode,
            phoneNumber: action.payload.phoneNumber,
            role: action.payload.role,
            stripePaymentMethodId: action.payload.stripePaymentMethodId,
            stripePriceId: action.payload.stripePriceId
        }, {
            headers: {
                'Authorization': `Bearer ${encToken}`
            }
        });

        const data = response.data;
        
        if (data?.createStripeAccountAndSubscribe?.success === true) {
            yield put({
                type: types.CREATE_STRIPE_ACCOUNT_AND_SUBSCRIBE_SUCCESS,
                payload: data?.createStripeAccountAndSubscribe?.message
            });
        } else {
            yield put({
                type: types.CREATE_STRIPE_ACCOUNT_AND_SUBSCRIBE_ERROR,
                payload: data?.createStripeAccountAndSubscribe?.message || '操作失败'
            });
        }
    } catch (err) {
        yield put({
            type: types.CREATE_STRIPE_ACCOUNT_AND_SUBSCRIBE_ERROR,
            payload: err.response?.data?.message || err.message || '请求异常'
        });
    }
}

export function* createStripeAccountAndSubscribeStartWatcherSaga() {
    yield takeEvery(types.CREATE_STRIPE_ACCOUNT_AND_SUBSCRIBE_START, createStripeAccountAndSubscribeStartHandlerSaga);
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 21:30:48