当我尝试通过 Angular HttpClient 下载和使用 Cloudinary 小部件 javascript 资源时,出现 CORS 错误。
到底是怎么回事?我对 HttpClient 或 CORS 并不陌生,但从未见过这个。
CORS 策略阻止了在“ https://widget.cloudinary.com/v2.0/global/all.js ”处访问 XMLHttpRequest从源“ http://127.0.0.1:4200 ”:没有“访问控制” -Allow-Origin' 标头存在于请求的资源上。
服务器CORS与此问题无关。它是公开可用的代码,可以在任何浏览器中轻松检索。
请求的脚本确实到达了我的 Chrome 开发工具/网络选项卡 XHR 部分。所以服务器发送了它,Chrome 很高兴地收到了它。
我在 Angular 开发环境中。
问题出在 Angular 上,我认为是 HttpClient。它认为存在不存在的 CORS 问题。
开发工具中的请求标头:Sec-Fetch-Mode:cors
我看过一堆其他 SO 帖子,包括一个看起来相似的帖子,但没有帮助。
我的代码。
export class CloudinaryComponent implements OnInit {
private url = 'https://widget.cloudinary.com/v2.0/global/all.js';
constructor(
private http: HttpClient
) {}
ngOnInit() {
this.loadWidget;
}
// Load the Cloudinary Upload Widget code, not the widget GUI.
private loadWidget() {
return this.http.get(this.url);
};
// Button click calls the Upload Widget GUI.
private callPopup() {
this.loadWidget().subscribe( result => {
// this.uploadWidget.open();
});
}
}
如何正确嵌入 Cloudinary 小部件?
不要忽略错误消息。CORS 问题与服务器没有提供正确的标头以允许从您的网站 javascript 代码进行跨源访问有关!正如错误所说
请求的资源上不存在“Access-Control-Allow-Origin”标头。
问题不在于您的客户端。Angular 不会产生这个错误。出于安全原因,您的浏览器正在阻止请求。服务器只是决定不允许此类请求。您可以直接从浏览器访问资源这一事实可能会欺骗您,但在这种情况下,您以不同的方式访问资源(即不是从 javascript XMLHttpRequest 访问)。
如果您想完全理解 CORS,请阅读 CORS:
https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS
XMLHttpRequest 无法加载 XXX No 'Access-Control-Allow-Origin' 标头
使用 HttpClient 下载 javascript 文件将无法使用小部件!您必须在 html 中嵌入 cloudinary js 文件才能使用它。
动态嵌入和创建 javascript 小部件的服务可能如下所示:
import { Injectable, RendererFactory2, Renderer2 } from '@angular/core';
import { Observable, of, fromEvent } from 'rxjs';
import { map } from 'rxjs/operators';
declare let cloudinary: any; // declare js widget variable
const widgetUrl = 'https://widget.cloudinary.com/v2.0/global/all.js';
@Injectable({
providedIn: 'root'
})
export class CloudinaryService {
private renderer: Renderer2;
constructor(rendererFactory: RendererFactory2) {
this.renderer = rendererFactory.createRenderer(null, null);
}
// create the upload widget
createUploadWidget(data: any, callback: (error: any, result: any) => void): Observable<any> {
return this.skriptExists(widgetUrl)
// js is embeded -> call js function directly
? of(cloudinary.createUploadWidget(data, callback))
// js isn't embeded -> embed js file and wait for it to load
: fromEvent(this.addJsToElement(widgetUrl), 'load').pipe(
// map to call of js function
map(e => cloudinary.createUploadWidget(data, callback))
);
}
// check if js file is already embeded
private skriptExists(jsUrl: string): boolean {
return document.querySelector(`script[src="${jsUrl}"]`) ? true : false;
}
// embed external js file in html
private addJsToElement(jsUrl: string): HTMLScriptElement {
const script = document.createElement('script');
script.type = 'text/javascript';
script.src = jsUrl;
this.renderer.appendChild(document.body, script);
return script;
}
}
使用组件中的服务来创建小部件:
export class AppComponent implements OnInit {
widget: any;
constructor(private cloudinary: CloudinaryService) { }
ngOnInit() {
this.cloudinary.createUploadWidget(
{
cloudName: 'my_cloud_name',
uploadPreset: 'my_preset'
},
(error, result) => {
if (!error && result && result.event === "success") {
console.log('Done! Here is the image info: ', result.info);
}
}
).subscribe(widget => this.widget = widget);
}
openWidget() {
if (this.widget) {
console.log('open')
this.widget.open();
}
}
}
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句