如何阻止HttpClient调用预签名URL时添加网关服务器域名
This is a super common headache when working with Angular + AWS S3 presigned URLs, and it almost always boils down to global HTTP interceptors or base URL configs overriding absolute URLs. Let’s walk through how to fix this properly:
1. Pinpoint the Root Cause
Angular’s HttpClient only appends a base URL to relative paths (like /api/upload). If your full S3 presigned URL (which should look like https://your-bucket.s3.amazonaws.com/your-file?X-Amz-Signature=...) is getting prefixed with your gateway domain, 99% of the time it’s because you have an HTTP interceptor that adds your API base URL to every request without checking if the URL is already absolute.
2. Fix the HTTP Interceptor
If you’re using an interceptor to inject your API base URL, modify it to skip absolute URLs. Here’s how to adjust it:
Before (Broken)
@Injectable() export class BaseUrlInterceptor implements HttpInterceptor { intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> { // This appends the base URL to EVERY request, including S3's absolute URLs const modifiedRequest = request.clone({ url: environment.apiBaseUrl + request.url }); return next.handle(modifiedRequest); } }
After (Fixed)
@Injectable() export class BaseUrlInterceptor implements HttpInterceptor { intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> { // Check if the URL is already absolute (starts with http/https) const isAbsoluteUrl = /^https?:\/\//i.test(request.url); if (!isAbsoluteUrl) { // Only append base URL to relative paths const modifiedRequest = request.clone({ url: environment.apiBaseUrl + request.url }); return next.handle(modifiedRequest); } // Let absolute S3 URLs pass through unchanged return next.handle(request); } }
3. Clean Up Your Upload Code
Your current code has a subtle issue with the Content-Type header that could cause S3 signature validation failures. FormData automatically sets the correct multipart/form-data header, so manually overriding it can break the presigned URL’s signature. Here’s the improved version:
private save(presignedUri: string, file: File): Observable<HttpEvent<any>> { const formData: FormData = new FormData(); formData.append('file', file); const req = new HttpRequest('POST', presignedUri, formData, { reportProgress: true, responseType: 'text', // Optional: Disable credentials since S3 doesn't need your app's cookies withCredentials: false }); return this.http.request(req); }
4. Double-Check the Presigned URL
Make sure your backend is returning a full absolute URL (not a relative path) for the presigned URI. If it’s sending something like /s3/upload?signature=... instead of https://your-bucket.s3.us-east-1.amazonaws.com/..., HttpClient will automatically append your gateway domain.
内容的提问来源于stack exchange,提问作者fezu54

