如何在 Angular 中动态嵌入来自 Cloudinary 的第三方 javascript 小部件?
Posted
技术标签:
【中文标题】如何在 Angular 中动态嵌入来自 Cloudinary 的第三方 javascript 小部件?【英文标题】:How to embed third party javascript widgets from Cloudinary dynamically in Angular? 【发布时间】:2020-01-13 19:09:26 【问题描述】:当我尝试通过 Angular HttpClient 下载和使用 Cloudinary 小部件 javascript 资源时遇到 CORS 错误。
发生了什么事?我对 HttpClient 或 CORS 并不陌生,但从未见过。
从源“http://127.0.0.1:4200”访问“https://widget.cloudinary.com/v2.0/global/all.js”处的 XMLHttpRequest 已被 CORS 策略阻止:请求的资源上不存在“Access-Control-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 小部件?
【问题讨论】:
【参考方案1】:问题
不要忽略错误消息。 CORS 问题与服务器未提供正确的标头以允许从您的网站 javascript 代码进行跨源访问有关!正如错误所说
请求的资源上不存在“Access-Control-Allow-Origin”标头。
问题不在于您的客户端。 Angular 不会产生这个错误。出于安全原因,您的浏览器正在阻止该请求。服务器刚刚决定不允许此类请求。您可以直接从浏览器访问资源这一事实可能会欺骗您,但在这种情况下,您以不同的方式访问资源(即不是从 javascript XMLHttpRequest)。
如果您想完全理解 CORS,请阅读它:
https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS
XMLHttpRequest cannot load XXX No 'Access-Control-Allow-Origin' header
解决方案
使用 HttpClient 下载 javascript 文件不会使您能够使用小部件!您必须将 cloudinary js 文件嵌入到您的 html 中才能使用它。
动态嵌入和创建 javascript 小部件的服务可能如下所示:
Demo
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();
【讨论】:
谢谢!我以前与 CORS 合作过,并认为我了解所有这些。他们的服务器似乎允许有限的请求。我正在通过 html 脚本设置获取信息,但这对我来说似乎很古怪。看来我应该只用脚本创建一个对象,然后用代码从那里开始。误导的是脚本下载,我可以在开发工具中看到它,所以服务器似乎没有问题。我可以看到我的实现是。 @Preston 如果您的整个应用程序都在使用 Cloudinary 小部件,并且您不介意在启动时加载 js,您显然可以将<script>
标签添加到您的index.html
。我假设您希望在初始化特定组件时根据特定请求动态加载脚本,这就是我回答中的 Service 所做的。
是的,你是对的。只有几个组件需要小部件。它是应用程序的一小部分。再次感谢您,我相信这个 Angular / Cloudinary 代码将来会对许多编码人员有用。网上没有这样的东西。以上是关于如何在 Angular 中动态嵌入来自 Cloudinary 的第三方 javascript 小部件?的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Angular 组件中正确使用 Cloud Functions?
存在安全漏洞的 Spring Cloud 嵌入式 netty 服务器