Fetch下载原理

本文介绍了Fetch下载的原理,通过fetch获取文件,将其转化为Blob对象,然后利用a标签结合BlobURL触发下载。文中还给出了Ant Design Pro中download组件的实现示例,详细阐述了如何将fetch获取的ArrayBuffer数据转换为可下载的文件。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


下载原理

在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函数的关键代码:
    在这里插入图片描述
  2. 将响应内容存到内存中(为blob)
    在这里插入图片描述
  3. 建立一个a标签执行blob,出发点击下载。
    在这里插入图片描述

总结

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

参考文献

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

### Fetch API 中 AbortController 的 abort 方法工作原理 AbortController 是一种 Web API 工具,专门设计用来控制和终止由 `fetch` 或其他异步操作发起的请求。通过创建一个 `AbortController` 实例并将其信号 (`signal`) 关联到 `fetch` 请求中,可以实现对请求生命周期的精确管理。 #### 创建控制器实例 首先,需要创建一个新的 `AbortController` 对象。这个对象提供了一个名为 `abort()` 的方法,用于触发请求的终止行为[^1]。 ```javascript const controller = new AbortController(); ``` #### 将信号关联至 fetch 请求 在执行 `fetch` 操作时,可以通过设置 `options` 参数中的 `signal` 属性,将上述控制器的信号绑定到该请求上。一旦调用了 `controller.abort()`,与之关联的所有请求都会被立即中断,并抛出特定错误 (DOMException)[^2]。 ```javascript const options = { method: 'GET', signal: controller.signal // 绑定信号 }; fetch('https://example.com/data', options).then(response => { console.log('Response received:', response); }).catch(error => { if (error.name === 'AbortError') { console.error('Fetch aborted'); } else { console.error('An error occurred:', error); } }); ``` #### 执行中止逻辑 当调用 `controller.abort()` 后,所有依赖于同一信号源的操作都将停止运行。对于 `fetch` 来说,这意味着 HTTP 连接会被关闭或者不再等待响应完成,从而释放资源[^3]。 ```javascript // 几秒后中止请求 setTimeout(() => { controller.abort(); // 触发中止机制 }, 5000); ``` 这种模式非常适合处理那些可能会因为外部条件改变而变得不必要的任务,例如用户导航离开当前页面前未加载完毕的数据获取过程[^4]。 ### 总结 AbortController 提供了一种优雅的方式来管理和优化应用内的异步活动流,特别是针对长时间运行或潜在冗余的任务提供了有效的解决方案。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值