Angular中如何实现两个API调用的事务性执行:全成功或全失败
Angular 实现两个API的事务性执行(失败回滚)
要实现「两个API要么都成功,要么都不生效」的需求,核心是串联API执行顺序+失败时触发回滚,RxJS的操作符可以帮你实现这个逻辑,但必须依赖后端提供第一个API的回滚接口(前端无法自行撤销POST请求的结果)。
核心逻辑
- 先执行第一个POST API(
saveMovementDetails),失败则直接终止,展示第一个API的错误 - 第一个API成功后,执行第二个PUT API(
saveTourDetails) - 若第二个API失败,立即调用第一个API的回滚接口,回滚成功后展示第二个API的错误
- 回滚本身失败时,需告知用户双重错误
代码实现
假设后端提供了回滚第一个API的方法(比如revertMovementDetails,传入创建成功的Movement ID),完整代码如下:
import { concatMap, catchError, throwError, EMPTY } from 'rxjs'; // 封装回滚逻辑,复用代码 const rollbackMovement = (movementId: string) => { return this.movementService.revertMovementDetails(movementId).pipe( catchError(rollbackErr => { // 记录回滚失败日志,可根据需求扩展 console.error('回滚Movement操作失败:', rollbackErr); return throwError(() => new Error('事务失败:保存Tour出错,且回滚Movement操作失败')); }) ); }; // 执行事务流程 this.movementService.saveMovementDetails(movData).pipe( // 第一个API成功后,执行第二个API,concatMap保证顺序执行 concatMap(savedMovement => { return this.tourService.saveTourDetails(tourId, tourData).pipe( // 捕获第二个API的错误,触发回滚 catchError(tourErr => { return rollbackMovement(savedMovement.id).pipe( // 回滚完成后,抛出原Tour错误,让上层处理展示 concatMap(() => throwError(() => tourErr)) ); }) ); }), // 统一处理所有错误 catchError(finalErr => { console.error('事务执行失败:', finalErr); // 这里替换成你的UI错误提示逻辑,比如弹窗/消息提示 // this.notification.error(finalErr.message); return EMPTY; // 返回空流避免订阅报错 }) ).subscribe({ next: () => { // 两个API都成功,执行成功逻辑 console.log('事务执行成功'); // this.notification.success('操作完成'); } });
关键细节说明
- 为什么不用forkJoin?:
forkJoin是并行发起两个请求,不符合「第一个失败则不执行第二个」的要求,且无法处理先成功后失败的回滚场景(第一个请求已经完成,无法终止) - 为什么mergeMap不行?:单纯用
mergeMap串联请求,不会在第二个API失败时触发回滚逻辑,必须在错误分支中主动加入回滚操作 - 回滚接口的必要性:前端无法直接撤销POST请求的数据库变更,必须由后端提供对应的反向操作(比如删除刚创建的Movement记录,或恢复原有状态)
错误场景处理
- 第一个API失败:直接进入最外层
catchError,展示第一个API的错误,第二个API不会被调用 - 第二个API失败:触发回滚操作,回滚成功后展示第二个API的错误;回滚失败则展示组合错误
- 回滚操作失败:记录日志并告知用户双重错误,确保用户知晓当前状态
内容的提问来源于stack exchange,提问作者blume0F
相关产品推荐
相关产品推荐

