NGRX Effects链式API调用异常:无网络请求返回旧数据求助
NGRX Effects链式异步流程异常:getShippingMethods请求未触发,返回旧数据
问题概述
使用CommerceTools + NGRX处理结账地址切换流程时,出现以下异常:
- 流程分为四步:重置配送地址→获取匹配配送方式→获取默认配送方式ID→设置默认配送方式,所有步骤依赖API调用
- 触发第一步后,
getShippingMethodsSuccessaction已触发,但对应GET请求未出现在网络面板,导致使用旧配送方式ID调用API时CommerceTools返回错误 - 部分场景(多次切换地址、延迟切换后快速操作)功能正常
核心原因分析
- GET请求浏览器缓存:
getShippingMethods接口使用GET请求,URL仅包含cartId,切换地址后cartId未变,浏览器缓存了旧响应,导致新请求未实际发送,直接返回旧数据 - 状态一致性问题:
getShippingMethodsSuccess未携带最新cart信息,后续流程从store获取的cart可能是旧版本,触发409版本冲突错误 - 竞态条件:快速操作时,异步流程的状态更新与action触发顺序不一致,导致数据不同步
修复方案
1. 禁用GET请求缓存
修改getShippingMethods方法,添加缓存控制头,强制浏览器不缓存响应:
import { HttpHeaders } from '@angular/common/http'; getShippingMethods(cart: Cart ) { const url = `${environment.commercetoolsURL}/${environment.commercetoolsProjectKey}/shipping-methods/matching-cart?cartId=${cart.id}`; const headers = new HttpHeaders({ 'Cache-Control': 'no-cache', Pragma: 'no-cache', Expires: '0' }); return this.http.get(url, { headers }).pipe(map((data: any) => data.results)); }
2. 传递最新cart信息,避免依赖旧store状态
修改Action定义
在fromActions.ts中更新getShippingMethodsSuccess,携带最新cart:
export const getShippingMethodsSuccess = createAction( '[Cart] Get Shipping Methods Success', props<{ shippingMethods: ShippingMethod[], cart: Cart }>() );
更新runGetShippingMethods$ Effect
触发成功action时传入最新cart:
runGetShippingMethods$ = createEffect(() => this.actions$.pipe( ofType(fromActions.getShippingMethods), mergeMap(({ cart }) => this._addressService.getShippingMethods(cart).pipe( map((shippingMethods: ShippingMethod[]) => fromActions.getShippingMethodsSuccess({ shippingMethods, cart }) ), catchError((err) => of(fromActions.getShippingMethodsFailed({ error: err }))) )) ) );
调整setDefaultShippingMethod$ Effect
直接使用action中的最新cart,不再从store获取:
setDefaultShippingMethod$ = createEffect(() => this.actions$.pipe( ofType(fromActions.getShippingMethodsSuccess), mergeMap(({ shippingMethods, cart }) => from(this._addressService.getDefaultShippingMethod(shippingMethods)).pipe( tap((defaultShippingMethod) => console.log(defaultShippingMethod)), mergeMap((shippingMethod: ShippingMethod) => [ fromActions.updateOrderData({ cart, actions: [ { action: 'setShippingMethod', data: { key: 'shippingMethod', value: { id: shippingMethod.id, typeId: 'shipping-method' }, }, }, ] }), ]), catchError((err) => { console.log(err); return of(fromActions.updateOrderDataFailed({ error: err })); }) ) ) ) );
3. 修正409重试时的cart版本
在updateOrderData$ Effect中,重试时更新cart对象的version,确保后续流程使用最新版本:
catchError((err) => { if (err.status === 409) { console.log('%c---version mismatch retry update order---', 'background: red; color: white; padding: 3px; border-radius: 2px;'); const newVersionNumber: number = err.error.errors[0].currentVersion; return of(fromActions.updateOrderData({ cart: { ...payload.cart, version: newVersionNumber }, // 更新cart的version actions: payload.actions, version: newVersionNumber })); } else { return of(fromActions.updateOrderDataFailed({ error: err })); } })
验证步骤
- 切换配送地址,查看网络面板确认
getShippingMethods请求每次都被发送 - 检查
getShippingMethodsSuccess返回的配送方式是否与新地址匹配 - 快速多次切换地址,确认流程无报错,CommerceTools端数据同步正确
内容的提问来源于stack exchange,提问作者rd.vdw
相关产品推荐
相关产品推荐

