Angular:Cloudinary 错误 “消息”:“cloud_name 已禁用”

Posted

技术标签:

【中文标题】Angular:Cloudinary 错误 “消息”:“cloud_name 已禁用”【英文标题】:Angular: Cloudinary error "message": "cloud_name is disabled" Angular:Cloudinary 错误 “消息”:“cloud_name 已禁用” 【发布时间】:2020-12-21 03:35:09 【问题描述】:

我正在尝试通过 Angular 使用 Cloudinary 图像上传。 我已经按照他们的文档安装了图片上传器 sdk。我已经关注了组件和 html 的一些示例项目。

在我的项目中一切正常,但是当我尝试上传图片时,我不断收到错误消息:

Upload completed with status code 401
error  "message": "cloud_name is disabled" 

这是我的component.ts

import  Component, OnInit, Input, NgZone  from '@angular/core';
import  HttpClient  from '@angular/common/http';
import  FileUploader, FileUploaderOptions, ParsedResponseHeaders, FileUploadModule  from 'ng2-file-upload';
import  Cloudinary  from '@cloudinary/angular-5.x';

// https://www.youtube.com/watch?v=YkvqLNcJz3Y

@Component(
  selector: 'app-cloudinary',
  templateUrl: './cloudinary.component.html',
  styleUrls: ['./cloudinary.component.scss']
)
export class CloudinaryComponent implements OnInit 

  @Input()
  responses: Array<any>;

  public hasBaseDropZoneOver: boolean = false;
  public uploader: FileUploader;
  private title: string;

  constructor(
    private cloudinary: Cloudinary,
    private zone: NgZone,
    private http: HttpClient
  ) 
    this.responses = [];
    this.title = '';
  

  ngOnInit(): void 
    // Create the file uploader, wire it to upload to your account
    const uploaderOptions: FileUploaderOptions = 
      url: `https://api.cloudinary.com/v1_1/$this.cloudinary.config().CLOUD_NAME/upload`,
      // Upload files automatically upon addition to upload queue
      autoUpload: true,
      // Use xhrTransport in favor of iframeTransport
      isHTML5: true,
      // Calculate progress independently for each uploaded file
      removeAfterUpload: true,
      // XHR request headers
      headers: [
        
          name: 'X-Requested-With',
          value: 'XMLHttpRequest'
        
      ]
    ;
    this.uploader = new FileUploader(uploaderOptions);

    this.uploader.onBuildItemForm = (fileItem: any, form: FormData): any => 
      // Add Cloudinary's unsigned upload preset to the upload form
      form.append('upload_preset', this.cloudinary.config().upload_preset);
      // Add built-in and custom tags for displaying the uploaded photo in the list
      let tags = 'myphotoalbum';
      if (this.title) 
        form.append('context', `photo=$this.title`);
        tags = `myphotoalbum,$this.title`;
      
      // Upload to a custom folder
      // Note that by default, when uploading via the API, folders are not automatically created in your Media Library.
      // In order to automatically create the folders based on the API requests,
      // please go to your account upload settings and set the 'Auto-create folders' option to enabled.
      form.append('folder', 'angular_sample');
      // Add custom tags
      form.append('tags', tags);
      // Add file to upload
      form.append('file', fileItem);

      // Use default "withCredentials" value for CORS requests
      fileItem.withCredentials = false;
      return  fileItem, form ;
    ;

    // Insert or update an entry in the responses array
    const upsertResponse = fileItem => 

      // Run the update in a custom zone since for some reason change detection isn't performed
      // as part of the XHR request to upload the files.
      // Running in a custom zone forces change detection
      this.zone.run(() => 
        // Update an existing entry if it's upload hasn't completed yet

        // Find the id of an existing item
        const existingId = this.responses.reduce((prev, current, index) => 
          if (current.file.name === fileItem.file.name && !current.status) 
            return index;
          
          return prev;
        , -1);
        if (existingId > -1) 
          // Update existing item with new data
          this.responses[existingId] = Object.assign(this.responses[existingId], fileItem);
         else 
          // Create new response
          this.responses.push(fileItem);
        
      );
    ;

    // Update model on completion of uploading a file
    this.uploader.onCompleteItem = (item: any, response: string, status: number, headers: ParsedResponseHeaders) =>
      upsertResponse(
        
          file: item.file,
          status,
          data: JSON.parse(response)
        
      );

    // Update model on upload progress event
    this.uploader.onProgressItem = (fileItem: any, progress: any) =>
      upsertResponse(
        
          file: fileItem.file,
          progress,
          data: 
        
      );
  

  updateTitle(value: string) 
    this.title = value;
  

  // Delete an uploaded image
  // Requires setting "Return delete token" to "Yes" in your upload preset configuration
  // See also https://support.cloudinary.com/hc/en-us/articles/202521132-How-to-delete-an-image-from-the-client-side-
  deleteImage = function (data: any, index: number) 
    const url = `https://api.cloudinary.com/v1_1/$this.cloudinary.config().CLOUD_NAME/delete_by_token`;
    const headers = new Headers( 'Content-Type': 'application/json', 'X-Requested-With': 'XMLHttpRequest' );
    const options =  headers: headers ;
    const body = 
      token: data.delete_token
    ;
    this.http.post(url, body, options).subscribe(response => 
      console.log(`Deleted image - $data.public_id $response.result`);
      // Remove deleted item for responses
      this.responses.splice(index, 1);
    );
  ;

  fileOverBase(e: any): void 
    this.hasBaseDropZoneOver = e;
  

  getFileProperties(fileProperties: any) 
    // Transforms javascript Object to an iterable to be used by *ngFor
    if (!fileProperties) 
      return null;
    
    return Object.keys(fileProperties)
      .map((key) => ( 'key': key, 'value': fileProperties[key] ));
  

这是我的component.html

<h1>Image Upload to Cloudinary TESTING</h1>

<div id="direct_upload" ng2FileDrop [uploader]="uploader" (fileOver)="fileOverBase($event)" [ngClass]="'nv-file-over': hasBaseDropZoneOver">
    <h1>New Photo</h1>
    <h2>Direct upload from the browser with Angular File Upload</h2>
    <p>You can also drag and drop an image file into the dashed area.</p>
    <form>
        <div class="form_line">
            <label path="title">Title:</label>
            <div class="form_controls">
                <input type="text" class="form-control" #title placeholder="Title" (keyup.enter)="updateTitle(title.value)" (blur)="updateTitle(title.value)"
                />
            </div>
        </div>
        <div class="form_line">
            <label>Image:</label>
            <div class="form_controls">
                <div class="upload_button_holder">
                    <label class="upload_button" for="fileupload">Upload</label>
                    <!-- onChange hanlder resets the input value to get the change event when uploading the same file consecutively -->
                    <input type="file" id="fileupload" #fileInput ng2FileSelect [style.display]="'none'" [uploader]="uploader" (change)="fileInput.value=''"
                        multiple />
                </div>

            </div>
        </div>
    </form> 
    <h2>Status</h2>
    <div class="file" *ngFor="let response of responses; let i = index">
        <h3>response.file.name</h3>
    <button class="delete-image" *ngIf="!!response.data.delete_token" (click)="deleteImage(response.data, i)">Delete image</button>
        <div class="status">
            Uploading... response.progress%
            <div *ngIf="!response.status">In progress</div>
            <div class="status-code" *ngIf="response.status">Upload completed with status code response.status</div>
        </div>
        <div class="progress-bar">
            <div class="progress" role="progressbar" [style.width.%]="response.progress"></div>
        </div>
        <div class="form_line">
            <div class="form_controls">
                <div class="preview">
                    <!-- Consider using https://github.com/valor-software/ng2-file-upload/issues/461 for image preview -->
                </div>
            </div>
        </div>
        <div class="info">
            <table>
                <tr *ngFor="let property of getFileProperties(response.data)">
                    <td>  property.key  </td>
                    <td>  property.value | json </td>
                </tr>
            </table>
        </div>
    </div>

</div>

在我的app.module.ts 中我做了我的导入:

...
import  CloudinaryModule, CloudinaryConfiguration  from '@cloudinary/angular-5.x';
import  Cloudinary  from 'cloudinary-core';
import  FileUploadModule  from "ng2-file-upload";

@NgModule(
  declarations: [
    ...
    CloudinaryComponent
  ],
  imports: [
    ...
    // Cloudinary import
    CloudinaryModule.forRoot(Cloudinary,  cloud_name: 'CLOUDN_NAME'  as CloudinaryConfiguration),
    FileUploadModule
  ],
  providers: [
    ...
  ],
  bootstrap: [AppComponent]
)


export class AppModule  

所以我真的不明白为什么它没有获得授权,但也让我感到困扰的是,在带有 Angular 的 Cloudinary 文档中,我看不到应该将我的 API KeyAPI Secret 放在哪里。

在我的项目中,我没有像 systemjs.config.js rollup-config.js 这样的文件。

如果有人可以帮助我,那就太棒了!

谢谢

【问题讨论】:

您好,好像是URL中的云名配置错误。尝试仅包含“CLOUD_NAME”(而不是 $this.cloudinary.config().CLOUD_NAME)。 【参考方案1】:

在您的示例中,您需要更改云 URL

你有https://api.cloudinary.com/v1_1/$this.cloudinary.config().CLOUD_NAME/upload,但你需要https://api.cloudinary.com/v1_1/CLOUD_NAME/upload

你的https://api.cloudinary.com/v1_1/$this.cloudinary.config().CLOUD_NAME/delete_by_token也需要改成https://api.cloudinary.com/v1_1/CLOUD_NAME/delete_by_token

您的upload_preset 需要将其从form.append('upload_preset', this.cloudinary.config().upload_preset) 更改为form.append('upload_preset', 'PRESET_NAME')

所以你的组件应该是这样的:

...
  ngOnInit(): void 
    // Create the file uploader, wire it to upload to your account
    const uploaderOptions: FileUploaderOptions = 
      url: `https://api.cloudinary.com/v1_1/$this.cloudinary.config().CLOUD_NAME/upload`,
      // Upload files automatically upon addition to upload queue
      autoUpload: true,
      // Use xhrTransport in favor of iframeTransport
      isHTML5: true,
      // Calculate progress independently for each uploaded file
      removeAfterUpload: true,
      // XHR request headers
      headers: [
        
          name: 'X-Requested-With',
          value: 'XMLHttpRequest'
        
      ]
    ;
    this.uploader = new FileUploader(uploaderOptions);

    this.uploader.onBuildItemForm = (fileItem: any, form: FormData): any => 
      // Add Cloudinary's unsigned upload preset to the upload form
      form.append('upload_preset', 'PRESET_NAME');
      // Add built-in and custom tags for displaying the uploaded photo in the list
      let tags = 'myphotoalbum';
      if (this.title) 
        form.append('context', `photo=$this.title`);
        tags = `myphotoalbum,$this.title`;
      
      // Upload to a custom folder
      // Note that by default, when uploading via the API, folders are not automatically created in your Media Library.
      // In order to automatically create the folders based on the API requests,
      // please go to your account upload settings and set the 'Auto-create folders' option to enabled.
      form.append('folder', 'angular_sample');
      // Add custom tags
      form.append('tags', tags);
      // Add file to upload
      form.append('file', fileItem);

      // Use default "withCredentials" value for CORS requests
      fileItem.withCredentials = false;
      return  fileItem, form ;
    ;
...
  // Delete an uploaded image
  // Requires setting "Return delete token" to "Yes" in your upload preset configuration
  // See also https://support.cloudinary.com/hc/en-us/articles/202521132-How-to-delete-an-image-from-the-client-side-
  deleteImage = function (data: any, index: number) 
    const url = `https://api.cloudinary.com/v1_1/CLOUD_NAME/delete_by_token`;
    const headers = new Headers( 'Content-Type': 'application/json', 'X-Requested-With': 'XMLHttpRequest' );
    const options =  headers: headers ;
    const body = 
      token: data.delete_token
    ;
...

对于API key,如果您要上传到签名的upload_preset,您可以像这样在组件中输入密钥,如sample project angular 所示:

...
 ngOnInit(): void 
   
    console.log("initialized");
    (window as any).cloudinary.createMediaLibrary(
      
        cloud_name: "<cloud name>",
        api_key: "<api key>",
        button_class: "myBtn",
        username: "<user email>",
        button_caption: "Select Image or Video"
      ,
...

【讨论】:

感谢您的回答!但是,我应该在某处提供 API 密钥和秘密吗?

以上是关于Angular:Cloudinary 错误 “消息”:“cloud_name 已禁用”的主要内容,如果未能解决你的问题,请参考以下文章

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

Cloudinary 与 Angular

Angular Cloudinary 使用重力

Angular cloudinary 自动播放具有响应宽度/高度的视频

使用变量时,Angular Cloudinary 宽度不起作用

Apollo-upload-client 与 Cloudinary