'f'
mh-two-thousand-and-two
2024-04-12 26f2711ef9461961fb953e2b497bd314ef95e345
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
import {
  fileToUrl,
  getFileName
} from 'uni-platform/helpers/file'
/**
 * 下载任务
 */
class DownloadTask {
  _xhr
  _callbacks = []
  constructor (xhr) {
    this._xhr = xhr
  }
 
  /**
   * 监听下载进度
   * @param {Function} callback 回调
   */
  onProgressUpdate (callback) {
    if (typeof callback !== 'function') {
      return
    }
    this._callbacks.push(callback)
  }
 
  offProgressUpdate (callback) {
    const index = this._callbacks.indexOf(callback)
    if (index >= 0) {
      this._callbacks.splice(index, 1)
    }
  }
 
  /**
   * 停止任务
   */
  abort () {
    if (this._xhr) {
      this._xhr.abort()
      delete this._xhr
    }
  }
}
/**
 * 下载文件
 * @param {*} param0
 * @param {string} callbackId
 * @return {DownloadTask}
 */
export function downloadFile ({
  url,
  header,
  timeout = (__uniConfig.networkTimeout && __uniConfig.networkTimeout.request) || 60 * 1000
}, callbackId) {
  const {
    invokeCallbackHandler: invoke
  } = UniServiceJSBridge
  var timer
  var xhr = new XMLHttpRequest()
  var downloadTask = new DownloadTask(xhr)
  xhr.open('GET', url, true)
  Object.keys(header).forEach(key => {
    xhr.setRequestHeader(key, header[key])
  })
  xhr.responseType = 'blob'
  xhr.onload = function () {
    clearTimeout(timer)
    const statusCode = xhr.status
    const blob = this.response
    let filename
    // 使用 getResponseHeader 跨域时会出现警告,但相比 getAllResponseHeaders 更方便
    const contentDisposition = xhr.getResponseHeader('content-disposition')
    if (contentDisposition) {
      // 暂时仅解析 filename 不解析 filename*
      const res = contentDisposition.match(/filename="?(\S+)"?\b/)
      if (res) {
        filename = res[1]
      }
    }
    blob.name = filename || getFileName(url)
    invoke(callbackId, {
      errMsg: 'downloadFile:ok',
      statusCode,
      tempFilePath: fileToUrl(blob)
    })
  }
  xhr.onabort = function () {
    clearTimeout(timer)
    invoke(callbackId, {
      errMsg: 'downloadFile:fail abort'
    })
  }
  xhr.onerror = function () {
    clearTimeout(timer)
    invoke(callbackId, {
      errMsg: 'downloadFile:fail'
    })
  }
  xhr.onprogress = function (event) {
    downloadTask._callbacks.forEach(callback => {
      var totalBytesWritten = event.loaded
      var totalBytesExpectedToWrite = event.total
      var progress = Math.round(totalBytesWritten / totalBytesExpectedToWrite * 100)
      callback({
        progress,
        totalBytesWritten,
        totalBytesExpectedToWrite
      })
    })
  }
  xhr.send()
  timer = setTimeout(function () {
    xhr.onprogress = xhr.onload = xhr.onabort = xhr.onerror = null
    downloadTask.abort()
    invoke(callbackId, {
      errMsg: 'downloadFile:fail timeout'
    })
  }, timeout)
  return downloadTask
}