Fetch下载原理

时间:2025-02-15 17:39:22
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 = (/.*(\.\w+)$/i, '$1') // const mimes = { // xlsx: 'application/', // } // 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> ) } }