如何在 Angular 中动态嵌入来自 Cloudinary 的第三方 javascript 小部件?

普雷斯顿

当我尝试通过 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' 标头存在于请求的资源上。

  1. 服务器CORS与此问题无关。它是公开可用的代码,可以在任何浏览器中轻松检索。

  2. 请求的脚本确实到达了我的 Chrome 开发工具/网络选项卡 XHR 部分。所以服务器发送了它,Chrome 很高兴地收到了它。

  3. 我在 Angular 开发环境中。

  4. 问题出在 Angular 上,我认为是 HttpClient。它认为存在不存在的 CORS 问题。

  5. 开发工具中的请求标头: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] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

如何在客户端blazor中动态加载第三方javascript?

如何在angular 6中捕获第三方库中的数据?

如何在Angular 2中封装第三方插件逻辑?

如何在ReactJS中调用第三方javascript函数

如何在Meteor.js中包含第三方JavaScript库?

如何在vue.js中包含第三方JavaScript文件?

如何根据第三方API响应添加窗口小部件字段?

在TypeScript中,如何修改第三方界面?

如何在CMake中包含来自第三方项目的选定来源

如何在 Eclipse 中抑制来自第三方源代码的 GCC 警告

如何在加载 AngularJS 之前初始化第三方 JavaScript 异步库

如何在Dragal 8中使用Packosist上未安装的第三方库安装第三方库?

如何在抖动中使用来自第三方包装资产的图像?

如何在Xcode中的调用堆栈中隐藏第三方调用

如何在Eclipse中的第三方库中设置断点?

如何在Maven POM中处理第三方JAR和远程存储库?

如何在 Odoo 中导入在第三方模块中声明的 Python 纯类?

如何在Firefox中为第三方Cookie创建例外?

如何在cmake中包含第三方工具?

如何在 django 中仅添加第三方应用程序所需的 url?

如何在第三方应用程序中屏蔽广告:Android

如何在Symfony 3.3中加载第三方库

如何在流星应用程序中添加第三方角度指令

如何在React钩子中初始化第三方库(konvajs)

如何在styles.xml中引用第三方库的attrs?

如何在Ant的javadoc任务中链接第三方库

如何在Selenium测试中阻止第三方脚本?

如何在Spring中自动为带有注释的第三方课程接线?

如何在Scala中更改,替换或扩展第三方枚举(Java)?