如何用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
相关产品推荐
相关产品推荐

