Fetch下载原理
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>
)
}
}