Angular 16跨域跳转双向JSON传参架构方案咨询
跨域站点间JSON传递与回调的标准实现(Angular 16)
针对你描述的a.com与B.com跨域JSON传递、处理后回调的场景,结合已实现SSO的前提,有两种成熟的标准方案,分别适配不同数据规模需求:
方案1:URL查询参数(适合小体积JSON)
适用场景:JSON数据体积小(通常≤2KB)、无敏感信息
核心逻辑:将JSON编码后通过URL查询参数传递,跳转完成后同样通过URL参数回调结果
- a.com生成JSON后转为Base64编码(避免特殊字符干扰URL解析),携带参数跳转至B.com
- B.com解析URL参数还原原始JSON,处理报表后生成新JSON,编码后跳转回a.com指定回调路由
- a.com解析回调URL的参数获取最终结果
方案2:共享后端存储(适合大体积/敏感JSON)
适用场景:JSON数据体积大、包含敏感信息
核心逻辑:利用SSO提供的用户身份,结合共享存储(如Redis、数据库)通过唯一ID传递数据
- a.com生成唯一ID(如UUID),将JSON存入共享存储并关联当前用户ID,跳转B.com时携带该ID
- B.com通过SSO获取用户ID,用唯一ID从存储中读取JSON,处理后将新JSON存入同一ID(或新ID),跳转回a.com并携带结果ID
- a.com用结果ID读取新JSON,完成后清理存储数据避免冗余
Angular 16 示例代码
方案1:a.com 发送数据并跳转
import { Component } from '@angular/core'; @Component({ selector: 'app-report-trigger', template: '<button (click)="navigateToReportSite()">生成报表</button>' }) export class ReportTriggerComponent { navigateToReportSite() { // 模拟用户选择生成的JSON数据 const userPayload = { selectedItems: ['item1', 'item3'], dateRange: { start: '2024-01-01', end: '2024-01-31' } }; // JSON转Base64编码 const encodedPayload = btoa(JSON.stringify(userPayload)); // 跳转至B.com报表页面 window.location.href = `https://b.com/report?payload=${encodedPayload}`; } }
方案1:B.com 接收数据并回调
import { Component, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; @Component({ selector: 'app-report-processor', template: '<div>报表处理中,请稍候...</div>' }) export class ReportProcessorComponent implements OnInit { constructor(private route: ActivatedRoute) {} ngOnInit() { this.route.queryParams.subscribe(params => { const encodedPayload = params['payload']; if (encodedPayload) { // 解码还原原始JSON const originalData = JSON.parse(atob(encodedPayload)); // 模拟报表处理逻辑,生成结果JSON const reportResult = { ...originalData, reportId: 'REP-2024-007', status: 'success', data: [/* 报表数据 */] }; // 编码结果并回调a.com const encodedResult = btoa(JSON.stringify(reportResult)); window.location.href = `https://a.com/report-result?result=${encodedResult}`; } }); } }
方案1:a.com 接收回调结果
import { Component, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; @Component({ selector: 'app-report-result', template: '<div>报表结果:{{reportResult | json}}</div>' }) export class ReportResultComponent implements OnInit { reportResult: any; constructor(private route: ActivatedRoute) {} ngOnInit() { this.route.queryParams.subscribe(params => { const encodedResult = params['result']; if (encodedResult) { this.reportResult = JSON.parse(atob(encodedResult)); } }); } }
方案2:a.com 存入共享存储并跳转
import { Component } from '@angular/core'; import { HttpClient } from '@angular/common/http'; import { v4 as uuidv4 } from 'uuid'; // 需安装依赖:npm install uuid @types/uuid @Component({ selector: 'app-report-trigger', template: '<button (click)="navigateToReportSite()">生成报表</button>' }) export class ReportTriggerComponent { constructor(private http: HttpClient) {} async navigateToReportSite() { const userPayload = { selectedItems: ['item1', 'item3'], dateRange: { start: '2024-01-01', end: '2024-01-31' } }; const dataId = uuidv4(); const userId = this.extractUserIdFromSSO(); // 将数据存入共享后端存储 await this.http.post('/api/shared-storage', { dataId, userId, data: userPayload }).toPromise(); // 跳转至B.com并携带dataId window.location.href = `https://b.com/report?dataId=${dataId}`; } // 从SSO Token中解析用户ID(示例逻辑,需匹配你的SSO实现) private extractUserIdFromSSO(): string { const ssoToken = localStorage.getItem('sso_token'); return ssoToken ? JSON.parse(atob(ssoToken.split('.')[1])).sub : ''; } }
方案2:B.com 读取数据并回调
import { Component, OnInit } from '@angular/core'; import { ActivatedRoute, HttpClient } from '@angular/router'; @Component({ selector: 'app-report-processor', template: '<div>报表处理中,请稍候...</div>' }) export class ReportProcessorComponent implements OnInit { constructor(private route: ActivatedRoute, private http: HttpClient) {} async ngOnInit() { this.route.queryParams.subscribe(async params => { const dataId = params['dataId']; if (dataId) { const userId = this.extractUserIdFromSSO(); // 从共享存储读取原始数据 const response = await this.http.get(`/api/shared-storage/${dataId}?userId=${userId}`).toPromise(); const originalData = (response as any).data; // 模拟报表处理生成结果 const reportResult = { ...originalData, reportId: 'REP-2024-007', status: 'success', data: [/* 报表数据 */] }; // 将结果存入共享存储 await this.http.put(`/api/shared-storage/${dataId}`, { userId, data: reportResult }).toPromise(); // 回调a.com并携带dataId window.location.href = `https://a.com/report-result?resultId=${dataId}`; } }); } private extractUserIdFromSSO(): string { const ssoToken = localStorage.getItem('sso_token'); return ssoToken ? JSON.parse(atob(ssoToken.split('.')[1])).sub : ''; } }
方案2:a.com 读取结果并清理存储
import { Component, OnInit } from '@angular/core'; import { ActivatedRoute, HttpClient } from '@angular/router'; @Component({ selector: 'app-report-result', template: '<div>报表结果:{{reportResult | json}}</div>' }) export class ReportResultComponent implements OnInit { reportResult: any; constructor(private route: ActivatedRoute, private http: HttpClient) {} async ngOnInit() { this.route.queryParams.subscribe(async params => { const resultId = params['resultId']; if (resultId) { const userId = this.extractUserIdFromSSO(); // 读取结果数据 const response = await this.http.get(`/api/shared-storage/${resultId}?userId=${userId}`).toPromise(); this.reportResult = (response as any).data; // 清理共享存储中的数据 await this.http.delete(`/api/shared-storage/${resultId}?userId=${userId}`).toPromise(); } }); } private extractUserIdFromSSO(): string { const ssoToken = localStorage.getItem('sso_token'); return ssoToken ? JSON.parse(atob(ssoToken.split('.')[1])).sub : ''; } }
关键注意事项
- URL参数方案需注意Base64编码后的总长度,超过浏览器URL限制(通常2KB)会导致数据截断,大体积数据优先选择共享存储方案
- 共享存储方案需添加数据过期机制,避免存储冗余;同时基于SSO用户ID做权限校验,防止数据越权访问
- 跳转前需确认SSO会话有效,避免用户需重新登录
内容的提问来源于stack exchange,提问作者Azure-Core
相关产品推荐
相关产品推荐

