.NET Core控制器中CancellationToken突然变为true的排查求助
问题根源分析
你的问题核心是异步代码执行顺序逻辑错误,再加上偶发的请求速度差异导致了现象不稳定:
- Angular的HTTP请求是异步非阻塞操作,
subscribe内部的回调函数只会在请求响应返回后才执行,但你把location.reload()放在了subscribe外部的同步代码块中。虽然代码里加了isDelete/isAdd/isUpdate的判断,但这些变量的赋值是在异步回调里,同步判断代码会在请求还未完成时就执行——此时变量还是初始的false,理论上不会触发刷新,但如果页面刷新逻辑意外执行(比如判断逻辑失效、误删条件),浏览器会立即终止所有未完成的HTTP请求,后端的CancellationToken就会被触发变为true。 - 偶发正常的原因:当本地调试时,后端接口在本地运行,请求响应速度极快,异步回调可能在页面刷新代码执行前刚好完成,此时请求已经处理完毕,页面刷新不会影响结果,所以看起来一切正常。这就是为什么问题有时会“自行消失”。
修复方案
方案1:将页面刷新逻辑移到异步回调内部
确保只有当请求成功完成后才执行页面刷新,避免终止未完成的请求:
修复后的deleteItems方法:
deleteItems(): void { const itemsToDelete = this.checkitems.map((item) => ({ uicp: item.uicp, dqcCode: item.dqcCode, dqcDescription: item.dqcDescription, task: Object.keys(item.tasks) .filter((task) => item.tasks[task]) .join(','), remark: item.remark, timestamp: item.lastUpdate, })); console.log(itemsToDelete); this.dataService.deleteData(itemsToDelete).subscribe((response) => { console.log('Items deleted:', response); if (response.status === 200) { this.tableData = this.tableData.filter( (item) => !this.checkitems.includes(item) ); this.checkitems = []; // 请求成功后再刷新页面 location.reload(); } }, (error) => { // 新增错误处理,避免请求失败后无反馈 console.error('删除失败:', error); }); }
修复后的saveItems方法(合并并发请求逻辑):
saveItems(): void { const requests: Observable<any>[] = []; const newItems = this.checkitems .filter((item) => item.isNew) .map((item) => ({ uicp: item.uicp, dqcCode: item.dqcCode, dqcDescription: item.dqcDescription, task: Object.keys(item.tasks) .filter((task) => item.tasks[task]) .join(','), remark: item.remark, })); const updatedItems = this.checkitems .filter((item) => !item.isNew) .map((item) => ({ uicp: item.uicp, dqcCode: item.dqcCode, dqcDescription: item.dqcDescription, task: Object.keys(item.tasks) .filter((task) => item.tasks[task]) .join(','), remark: item.remark, timestamp: item.lastUpdate, })); if (newItems.length > 0) { requests.push(this.dataService.addData(newItems)); } if (updatedItems.length > 0) { requests.push(this.dataService.updateData(updatedItems)); } if (requests.length > 0) { forkJoin(requests).subscribe( (responses) => { this.checkitems.forEach((item) => { item.isNew = false; item.selected = false; }); this.checkitems = []; // 所有请求完成后再刷新页面 location.reload(); }, (error: HttpErrorResponse) => { console.error('保存失败:', error.message); } ); } }
方案2:用async/await简化异步逻辑
将Observable转换为Promise,用async/await让代码逻辑更直观:
import { firstValueFrom } from 'rxjs'; async deleteItems(): Promise<void> { const itemsToDelete = this.checkitems.map((item) => ({ uicp: item.uicp, dqcCode: item.dqcCode, dqcDescription: item.dqcDescription, task: Object.keys(item.tasks) .filter((task) => item.tasks[task]) .join(','), remark: item.remark, timestamp: item.lastUpdate, })); console.log(itemsToDelete); try { const response = await firstValueFrom(this.dataService.deleteData(itemsToDelete)); if (response.status === 200) { this.tableData = this.tableData.filter( (item) => !this.checkitems.includes(item) ); this.checkitems = []; location.reload(); } } catch (error) { console.error('删除失败:', error); } }
额外注意事项
- 永远不要在HTTP请求未完成时执行页面刷新、路由跳转等操作,这些操作会直接终止当前页面的所有未完成请求,触发后端
CancellationToken。 - 必须添加错误回调,避免请求失败后无任何反馈,方便快速排查问题。
- 处理多并发请求时,使用
forkJoin合并Observable,确保所有请求都完成后再执行后续操作,避免部分请求未完成就刷新页面。
内容的提问来源于stack exchange,提问作者AoLiGei
相关产品推荐
相关产品推荐

