Fetch下载原理

文章目录

  • 下载原理
  • 实例
  • 总结
  • 参考文献


下载原理

在fetch中,先fetch文件,生成一个Blob,然后建立一个a标签,将连接连接到blob上,出发点击,就实现了下载。

实例

下面时ant-design-pro中download组件的实现。

export default class Download extends PureComponent {
  static propTypes = {
    action: string,
    accept: string,
    method: string,
    params: object,
    callback: func,
    beforeDownload: func,
  }

  static defaultProps = {
    action: '/sys/fileManage/downloadFile',
    accept: '*/*',
    method: 'GET',
    params: {},
    callback: () => {},
    beforeDownload: async () => {},
  }

  constructor(props) {
    super(props)
    this.state = {
      loading: false,
    }
  }

  downFile = (blob, fileName) => {
    if (window.navigator.msSaveOrOpenBlob) {
      navigator.msSaveBlob(blob, fileName)
    } else {
      const link = document.createElement('a')
      link.href = window.URL.createObjectURL(blob)
      link.download = fileName
      link.click()
      window.URL.revokeObjectURL(link.href)
    }
  }

  downloadTmpl = () => {
    const { params = {}, accept, method, action, callback } = this.props

    const headers = {
      ...(Cookies.get('token') ? { Authorization: Cookies.get('token') } : null),
      Accept: accept,
    }

    const request = extend({
      errorHandler, // 默认错误处理
      credentials: 'include', // 默认请求是否带上cookie
    })
    this.setState({
      loading: true,
    })
    return request(action, {
      method,
      headers,
      responseType: 'arrayBuffer',
      getResponse: true,
      params,
      ...(Object.keys(params).length ? { data: JSON.stringify(params) } : null),
    })
      .then(({ data, response }) => {
        if (data.code && data.code === 1000) {
          const { code, msg } = data
          const errorDesc = {
            message: `请求错误 ${code}`,
            description: msg,
          }
          notification.error(errorDesc)
          return
        }
        const contentDisposition = response.headers.get('content-disposition')
        let [fileName] = contentDisposition.split('=').slice(-1)
        fileName = fileName.replace(`utf-8''`, '')
        // const suffix = fileName.replace(/.*(\.\w+)$/i, '$1')
        // const mimes = {
        //   xlsx: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
        // }
        // const blob = new Blob([data], {
        //   ...(mimes[suffix.toUpperCase()] ? { type: mimes[suffix.toUpperCase()] } : null),
        // })
        const blob = new Blob([data])
        this.downFile(blob, decodeURI(fileName))
      })
      .then(() => callback())
      .finally(() => {
        this.setState({ loading: false })
      })
  }

  start = () => {
    const { beforeDownload } = this.props
    beforeDownload()
      .then(() => this.downloadTmpl())
      .catch(e => message.error(e.message))
  }

  render() {
    const { loading } = this.state
    const { children } = this.props
    return (
      <div onClick={this.start} style={{ display: 'inline-block' }}>
        {children({ loading })}
      </div>
    )
  }
}

使用render属性将Download组件内部状态loading暴露出去。

  1. fetch获取响应类型为ArrayBuffer的数据。 下面是downloadTmpl函数的关键代码:
    Fetch下载原理_第1张图片
  2. 将响应内容存到内存中(为blob)
    Fetch下载原理_第2张图片
  3. 建立一个a标签执行blob,出发点击下载。
    Fetch下载原理_第3张图片

总结

在fetch中,先fetch文件(响应类型为arrayBuffer),生成一个Blob,然后建立一个a标签,将连接连接到blob上,出发点击,就实现了下载。

参考文献

React中使用fetch实现文件上传下载

你可能感兴趣的:(ant-design-pro)