upload-file.js 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  1. /*
  2. * Copyright (C) 2020 Tencent Cloud.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. import UUID from 'uuid';
  17. import { getMediaType } from './utils';
  18. /**
  19. * 上传文件到腾讯云COS(需要调用云函数签名,请先配置好云函数)
  20. * @async
  21. * @param {string|File} file - 需要上传的文件,小程序环境选择的filePath或H5环境选择的File对象
  22. * @param {string?} key - 存储在COS上的文件名称,如果不传,则会生成uuid代替
  23. * @param {function?} onProgressUpdate - 上传进度回调,回调参数详见uni.uploadFile API
  24. * @return {Promise<string>} 返回成功上传到COS上的文件名称
  25. */
  26. export default async function uploadFile(file, key, onProgressUpdate) {
  27. if (!file) {
  28. throw new Error('file不能为空');
  29. }
  30. // 获取签名信息
  31. const { result } = await uniCloud.callFunction({
  32. name: 'tencentcloud-plugin',
  33. data: {
  34. module: 'COS',
  35. action: 'signPostObjectAPI',
  36. },
  37. });
  38. const signData = result;
  39. return new Promise((resolve, reject) => {
  40. let filePath = undefined;
  41. let fileExt;
  42. if (typeof file === 'string') {
  43. filePath = file;
  44. file = undefined;
  45. fileExt = filePath.split('?')[0].split('.').pop();
  46. } else {
  47. fileExt = file.name.split('.').pop();
  48. }
  49. // 支付宝小程序上传文件API必传fileType
  50. // 通过支付宝小程序环境下选择文件的时候,通过返回的filePath取得的扩展名可能是image/video/audio
  51. let fileType = undefined;
  52. // ifdef MP-ALIPAY
  53. if (fileExt === 'image') {
  54. fileExt = 'jpg';
  55. } else if (fileExt === 'video') {
  56. fileExt = 'mp4';
  57. } else if (fileExt === 'audio') {
  58. fileExt = 'mp3';
  59. }
  60. fileType = getMediaType(fileExt);
  61. // endif
  62. if (!key) {
  63. key = `${UUID.v1()}.${fileExt}`;
  64. }
  65. const uploadTask = uni.uploadFile({
  66. url: signData.host,
  67. file,
  68. filePath,
  69. fileType,
  70. name: 'file',
  71. formData: {
  72. key,
  73. 'q-sign-algorithm': signData.signAlgorithm,
  74. 'q-ak': signData.ak,
  75. 'q-key-time': signData.keyTime,
  76. 'q-signature': signData.signature,
  77. 'policy': signData.policy
  78. },
  79. success(response) {
  80. if (response.statusCode !== 204) {
  81. reject(new Error('文件上传失败'));
  82. } else {
  83. resolve(key);
  84. }
  85. },
  86. complete(r){
  87. },
  88. fail(error) {
  89. // 支付宝小程序环境下会将返回的204状态码识别为异常而触发fail回调,实际上是上传成功了的
  90. if (error.statusCode === 204) {
  91. resolve(key);
  92. } else {
  93. reject(error);
  94. }
  95. }
  96. });
  97. onProgressUpdate && uploadTask.onProgressUpdate(onProgressUpdate);
  98. });
  99. };