upload-file.js 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  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. console.log(signData)
  40. return new Promise((resolve, reject) => {
  41. let filePath = undefined;
  42. let fileExt;
  43. if (typeof file === 'string') {
  44. filePath = file;
  45. file = undefined;
  46. fileExt = filePath.split('?')[0].split('.').pop();
  47. } else {
  48. fileExt = file.name.split('.').pop();
  49. }
  50. // 支付宝小程序上传文件API必传fileType
  51. // 通过支付宝小程序环境下选择文件的时候,通过返回的filePath取得的扩展名可能是image/video/audio
  52. let fileType = undefined;
  53. // ifdef MP-ALIPAY
  54. if (fileExt === 'image') {
  55. fileExt = 'jpg';
  56. } else if (fileExt === 'video') {
  57. fileExt = 'mp4';
  58. } else if (fileExt === 'audio') {
  59. fileExt = 'mp3';
  60. }
  61. fileType = getMediaType(fileExt);
  62. // endif
  63. if (!key) {
  64. key = `${UUID.v1()}.${fileExt}`;
  65. }
  66. const uploadTask = uni.uploadFile({
  67. url: signData.host,
  68. file,
  69. filePath,
  70. fileType,
  71. name: 'file',
  72. formData: {
  73. key,
  74. 'q-sign-algorithm': signData.signAlgorithm,
  75. 'q-ak': signData.ak,
  76. 'q-key-time': signData.keyTime,
  77. 'q-signature': signData.signature,
  78. 'policy': signData.policy
  79. },
  80. success(response) {
  81. if (response.statusCode !== 204) {
  82. reject(new Error('文件上传失败'));
  83. } else {
  84. resolve(key);
  85. }
  86. },
  87. fail(error) {
  88. // 支付宝小程序环境下会将返回的204状态码识别为异常而触发fail回调,实际上是上传成功了的
  89. if (error.statusCode === 204) {
  90. resolve(key);
  91. } else {
  92. reject(error);
  93. }
  94. }
  95. });
  96. onProgressUpdate && uploadTask.onProgressUpdate(onProgressUpdate);
  97. });
  98. };