阅读 17842

文件直传 OSS 实践(三):Angular 篇

前言

《文件直传 OSS 实践(一):服务端篇》文章中讲解了如何在服务端生成用于客户端直传 OSS 的直传传凭证,本文讲解在使用 Angular 框架的 Web 页面中将文件直传 OSS 的整体流程。相对于在小程序中使用已经由官方封装好的上传方法,在 Angular 中使用上传功能会稍微复杂一些。 ​

获取直传凭证

我们假定获取直传凭证的 API 为: ​

GET https://api.xxx.com/upload/token
复制代码

可以将请求获取直传传凭证的过程进行封装(为方便演示,将所有的方法均放在了 app.component.ts 文件中,实际上涉及 HTTP 请求的方法应放在 *.service.ts 文件中): ​

// app.component.ts
import { HttpClient } from '@angular/common/http'
import { Component } from '@angular/core'

/** 直传凭证 */
export interface UploadToken {
  key: string
  policy: string
  signature: string
  OSSAccessKeyId: string
  url: string
}

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss'],
})
export class AppComponent {
  constructor(private http: HttpClient) {}

  token!: UploadToken

  /** 获取直传凭证 */
  getUploadToken() {
    this.http.get('https://api.xxx.com/upload/token').subscribe((data: UploadToken) => {
      this.token = data
    })
  }
}
复制代码

选择文件

相对于在小程序中可以直接使用 wx.chooseMedia 方法获取资源的路径,在 Angular 获取资源的路径会稍微复杂一些,需要在文档中获取到上传文件使用的子组件,然后再在其内部获取到文件路径。 ​

首先,定义 HTML 模板。 ​

// app.component.html
<input #uploader type="file" />
复制代码

这是一个获取文件的输入框,其中 #uploader 表示模板名,可用于在 *.component.ts 文件中获取该模板。需要使用 ViewChild 装饰器获取该模板。 ​

import { HttpClient } from '@angular/common/http'
import { Component, ElementRef, ViewChild } from '@angular/core'

/** 直传凭证 */
export interface UploadToken {
  key: string
  policy: string
  signature: string
  OSSAccessKeyId: string
  url: string
}

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss'],
})
export class AppComponent {
  constructor(private http: HttpClient) {}

  @ViewChild('uploader')
  FileElement!: ElementRef

  token!: UploadToken

  /** 获取直传凭证 */
  getUploadToken() {
    this.http.get('https://api.xxx.com/upload/token').subscribe((data: UploadToken) => {
      this.token = data
    })
  }

  /** 显示第一个文件的路径 */
  showFile() {
    console.log(this.FileElement.nativeElement.files[0])
  }
}

复制代码

核心部分为:

  @ViewChild('uploader')
  FileElement!: ElementRef
复制代码

其中,各部分的含义是: (1)'uploader'<input #uploader type="file" /> 中的 uploader 对应。 (2)! 为非空断言。 ​

在点击绑定的按钮选择文件后,调用 showFile 方法可以查看选中的文件。 ​

上传文件

获取到文件和上传凭证后,然后进行上传流程。这里需要注意的一点是:在添加 FormData 属性时,需要把 file 项放在最后,否则会失败。 ​

import { HttpClient } from '@angular/common/http'
import { Component, ElementRef, ViewChild } from '@angular/core'

/** 直传凭证 */
export interface UploadToken {
  key: string
  policy: string
  signature: string
  OSSAccessKeyId: string
  url: string
}

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss'],
})
export class AppComponent {
  constructor(private http: HttpClient) {}

  @ViewChild('uploader')
  FileElement!: ElementRef

  token!: UploadToken

  /** 获取直传凭证 */
  getUploadToken() {
    this.http.get('https://api.xxx.com/upload/token').subscribe((data: UploadToken) => {
      this.token = data
    })
  }

  /** 显示第一个文件的路径 */
  showFile() {
    console.log(this.FileElement.nativeElement.files[0])
  }

  /** 直传至 OSS */
  upload() {
    const file = this.FileElement.nativeElement.files[0]
    const formData = new FormData()
    formData.append('OSSAccessKeyId', this.token.OSSAccessKeyId)
    formData.append('key', this.token.key)
    formData.append('policy', this.token.policy)
    formData.append('signature', this.token.signature)
    formData.append('file', file)

    this.http.post(this.token.url, formData).subscribe((data: any) => {
      // 打印最终的资源 URL 地址
      console.log(this.token.url + '/' + this.token.key)
    })
  }
}
复制代码
文章分类
前端