Angular ngx-extended-pdf-viewer加载AWS S3文件遇CORS权限问题
问题详情
在Angular项目中使用ngx-extended-pdf-viewer加载AWS S3存储桶内的PDF文件时,触发CORS拦截,提示目标资源不存在Access-Control-Allow-Origin头。尽管已为域名https://selvamanidevsaas.selvamani.app配置了CORS源,问题仍未解决。
补充信息
- PDF文件通过PHP Laravel后端上传至S3存储桶
- 已在S3配置中添加
https://selvamanidevsaas.selvamani.app为允许的CORS源
报错信息
从源'https://selvamanidevsaas.selvamani.app'获取'https://s3bucket.s3.ap-south-1.amazonaws.com/work_permit/work_permit_1657881550.pdf'的请求被CORS策略阻止:请求资源上不存在'Access-Control-Allow-Origin'头。若可接受不透明响应,可将请求模式设为'no-cors'以禁用CORS获取资源。
UnknownErrorException {message: 'Failed to fetch', name: 'UnknownErrorException', details: 'TypeError: Failed to fetch'} details: "TypeError: Failed to fetch" message: "Failed to fetch" name: "UnknownErrorException"
解决方案
1. 修正S3存储桶的CORS规则
确保S3的CORS配置包含PDF加载所需的必要规则,涵盖允许的源、HTTP方法和响应头:
[ { "AllowedHeaders": ["*"], "AllowedMethods": ["GET", "HEAD", "OPTIONS"], "AllowedOrigins": ["https://selvamanidevsaas.selvamani.app"], "ExposeHeaders": ["Content-Range", "Content-Length", "ETag"] } ]
配置保存后等待几分钟让S3生效。
2. 检查Laravel上传时的对象配置
Laravel上传文件到S3时,需确保对象权限和元数据设置正确:
- 设置
public-read类的ACL,保证文件可被访问 - 可选:直接为对象添加
Access-Control-Allow-Origin响应头
示例上传代码:
use Illuminate\Support\Facades\Storage; Storage::disk('s3')->put( 'work_permit/work_permit_1657881550.pdf', $fileContent, [ 'ACL' => 'public-read', 'Content-Type' => 'application/pdf', 'Access-Control-Allow-Origin' => 'https://selvamanidevsaas.selvamani.app' ] );
3. 配置ngx-extended-pdf-viewer的请求参数
在Angular模板中为viewer设置HTTP请求头,确保请求符合CORS要求:
<ngx-extended-pdf-viewer [src]="pdfUrl" [httpHeaders]="{'Origin': 'https://selvamanidevsaas.selvamani.app'}" useBrowserLocale="true" ></ngx-extended-pdf-viewer>
若需支持PDF分段加载,需确保S3 CORS规则已允许Range方法及对应响应头。
4. 清除缓存与CDN刷新
- 清空浏览器缓存,避免复用旧的CORS响应
- 若S3前端配置了CloudFront等CDN,刷新CDN缓存,确保新规则生效
5. 应急临时方案(不推荐生产环境)
若无法快速调整S3配置,可通过Angular HttpClient以no-cors模式获取PDF blob,转换为本地URL后传给viewer:
import { HttpClient } from '@angular/common/http'; import { Component, OnInit, OnDestroy } from '@angular/core'; @Component({ selector: 'app-pdf-viewer', templateUrl: './pdf-viewer.component.html' }) export class PdfViewerComponent implements OnInit, OnDestroy { pdfUrl: string | undefined; constructor(private http: HttpClient) {} ngOnInit(): void { const s3PdfUrl = 'https://s3bucket.s3.ap-south-1.amazonaws.com/work_permit/work_permit_1657881550.pdf'; this.http.get(s3PdfUrl, { responseType: 'blob', mode: 'no-cors' }) .subscribe(blob => { this.pdfUrl = URL.createObjectURL(blob); }); } ngOnDestroy(): void { if (this.pdfUrl) { URL.revokeObjectURL(this.pdfUrl); } } }
注意:此方法会生成不透明响应,无法支持分段加载,大文件可能出现加载异常。
内容的提问来源于stack exchange,提问作者Selvamani P

