收藏
回答

小程序正式版用阿里云服务器上传文件时,已经后台添加了request合法域名,上传还是报错,为什么?

<script>
import ActivityService from "@/app/service/activityService.js";
const ActivityServices = new ActivityService();
import CryptoJS from 'crypto-js';
import { Base64 } from 'js-base64';
let uid = 0
export default {
  props: {
    showInfo:{
      type:Object,
      default:{
        from:'release',
        loadingText:true,
        maxNum:true,
        showPreview:true,


      }
    },
    userId: {
      type: String,
      required: true
    },
    initFileList: {
      type: Array,
      default: []
    },
    // 0:图片 1:视频
    fileType: {
      type: Number,
      default: 0
    },
    activityId: String,
    recordingParams: Object,
    cameraParams: Object,
    ossConfig: {
      region: "yourRegion",
      accessKeyId: "yourAccessKeyId",
      accessKeySecret: "yourAccessKeySecret",
      stsToken: "yourSecurityToken",
      bucket: "examplebucket",
      authorizationV4: true
    }
  },
  computed: {
    activity_info() {
      return this.$store.getters['activity/activity_info']
    },
  },
  watch: {
    // 监听props变化
    initFileList: {
      immediate: true,
      handler(newVal) {
        if (newVal) {
          console.log(this.activityId,"活动ID")
          console.log(newVal)
          this.fileList = [...newVal].filter(item=>item.url).map(item=>{
            item.preview = item.url;
            return item;
          })
        }else{
          console.log(newVal)
        }
      }
    }
  },
  data() {
    return {
      fileList: [], // 文件列表
      uploading: false,
      progress: 0,
      previewUrl: '',
      currentFile: null,
      files:null,
    }
  },


  methods: {
    async handleUpload() {
      if (this.uploading) return


      try {
        // 1. 选择文件
        const files = await this.chooseMedia()
        this.files =files;
        console.log(files,"files")
        if (!files.length) return


        // 2. 校验文件
        const validFiles = this.validateFiles(files)
        this.fileList = [...this.fileList, ...validFiles]


        // 3. 逐个上传
        for (const file of validFiles) {
          await this.uploadFile(file)
        }


        uni.showToast({ title: '全部上传完成' })
      } catch (error) {
        // debugger
        // uni.showToast({ title: error.errMsg, icon: 'none' })
      } finally {
        this.uploading = false
      }
    },


    // 统一选择媒体文件
    chooseMedia() {
      return new Promise((resolve, reject) => {
        wx.requirePrivacyAuthorize({
          success: () => {
            uni.chooseMedia({
              count: 4 - this.fileList.length, // 剩余可选数量
              mediaType: ['image', 'video'],
              sourceType: ['album', 'camera'],
              maxDuration: 30, // 视频最大时长30秒
              success: res => resolve(res.tempFiles),
              fail: reject
            })
          },
          fail: () => {
            // 用户拒绝,提示引导
            wx.showToast({
              title: '需同意隐私协议才能使用该功能',
              icon: 'none'
            });
          }
      })
    })
    },
    // 文件校验
    validateFiles(files) {
      return files.map(file => {
        const isVideo = file.fileType === 'video'
        const maxSize = isVideo ? 10 * 1024 * 1024 : 2 * 1024 * 1024


        if (file.size > maxSize) {
          throw new Error(`${isVideo ? '视频' : '图片'}大小不能超过${isVideo ? 10 : 2}MB`)
        }


        return {
          uid: uid++,
          type: file.fileType,
          name: file.tempFilePath.split('/').pop(),
          size: file.size,
          preview: file.tempFilePath,
          progress: 0,
          status: 'pending'
        }
      })
    },
    // 新增:读取文件内容
    readFileContent(tempFilePath) {
      return new Promise((resolve, reject) => {
        uni.getFileSystemManager().readFile({
          filePath: tempFilePath,
          success: res => resolve(res.data),
          fail: err => reject(new Error('文件读取失败'))
        });
      });
    },
    // 单个文件上传
    async uploadFile(file) {
      try {
        file.status = 'uploading';
        
        // 1. 获取OSS配置
        const ossConfig = await ActivityServices.getAliyunConfig({
          user_id: this.userId,
          file_name: file.name,
          file_type: file.type === 'video' ? 1 : 0
        });


        // 2. 读取文件内容
        // const fileContent = await this.readFileContent(file.preview);
        
        // 3. 上传到OSS
        const ossUrl = await this.uploadToOSS(file,
          ossConfig.data.data
        );


        // 4. 更新文件状态
        file.progress = 100;
        file.status = 'success';
        file.url = ossUrl;


        // 5. 视频需要通知后台
        // if (file.type === 'video') {
        //   await this.notifyBackend(ossUrl);
        // }
      } catch (error) {
        file.status = 'error';
        throw error;
      }
    },
    formatEndpoint(endpoint) {
      if (endpoint.startsWith('http://')) return endpoint;
      if (endpoint.startsWith('https://')) return endpoint;
      return `https://${endpoint}`;
    },
    getMimeType(fileType) {
      const types = {
        image: 'image/jpeg',
        video: 'video/mp4'
      };
      return types[fileType] || 'application/octet-stream';
    },
    getUTCDate() {
      const expiration = new Date();
      expiration.setUTCHours(expiration.getUTCHours() + 1);
      return expiration.toISOString().split('.')[0] + 'Z'; // 去除毫秒
    },
    async uploadToOSS(file,config) {
       try {
          // 生成 Policy
        const policy = {
          expiration: this.getUTCDate(config.expiration),
          conditions: [
            ['content-length-range', 0, 104857600],
            ['eq', '$bucket', config.bucket],
            ['starts-with', '$key', `${this.userId}/`] 
          ]
        };
        const policyBase64 = Base64.encode(JSON.stringify(policy)); 


        // 计算 Signature
        const signature = CryptoJS.HmacSHA1(policyBase64, config.access_key_secret)
          .toString(CryptoJS.enc.Base64);
        const fileName = `${this.userId}/${Date.now()}_${file.name}`;
        const formData = {
          key: fileName,
          OSSAccessKeyId: config.access_key_id,
          policy: policyBase64,
          signature: signature,
          'x-oss-security-token': config.security_token
        };
        console.log(formData,"formData")
        const endpoint = config.endpoint
        .replace('https//', '') // 修正用户示例中的错误格式
        .replace(/^(http:\/\/|https:\/\/)/, '') // 移除可能存在的协议头
        const uploadRes = await uni.uploadFile({
          url: `https://${config.bucket}.${endpoint}`,
          filePath: file.preview,
          name: 'file',
          formData: formData
        });


        if (uploadRes.statusCode === 204) {
          this.uploadResult = "上传成功";
          console.log("imgUrl:" ,`https://${config.bucket}.${endpoint}/${fileName}`)
          const uploadImgUrl = `https://${config.bucket}.${endpoint}/${fileName}`;
          // https://wq-image.oss-cn-beijing.aliyuncs.com/xiaobaibai/1747571994354_xBHNLh7uEbJ39969f668b97a0b5ce473f96cba31918d.png
          this.uploadComplete(uploadImgUrl, file)
        } else {
          console.log(uploadRes.data,"上传失败")
          this.uploadResult = `上传失败: ${uploadRes.data}`;
        }
      } catch (err) {
        console.error("上传失败33:", err);
        this.uploadResult = "上传失败";
      }
    },
    uploadComplete(fileUrl, file){
      const param = {
        user_id:this.userId,
        video_url:fileUrl,
        type:file.type === 'video' ? 1 : 0,
        privacy:0, // 0:公开 1:隐藏
        sence:0 //0:个人相册 1:活动相册
      }
      if(this.activity_info.activity_id){
        param.activity_id=this.activity_info.activity_id
      }
      ActivityServices.uploadData(param).then(res=>{
        console.log(res,"complete")
        if (res.data.code === 0 && res.data.data && res.data.data.video_url) {
          this.fileList = this.fileList.map(item => {
            const newItem = {...item}
            if (item.uid === file.uid) {
              newItem.url = res.data.data.video_url
            }
            return newItem
          })
          this.$emit('fileListChange', this.fileList)
        }
      })
    },
    removeFile(index) {
      if (this.uploading) return
      this.fileList.splice(index, 1)
      this.$emit('fileListChange', this.fileList)
    },


    // 格式化文件大小
    formatSize(bytes) {
      const units = ['B', 'KB', 'MB', 'GB']
      let size = bytes
      let unitIndex = 0
      
      while (size >= 1024 && unitIndex < units.length - 1) {
        size /= 1024
        unitIndex++
      }
      
      return `${size.toFixed(1)}${units[unitIndex]}`
    },
    // 通知后端
    async notifyBackend(ossUrl) {
      const params = {
        userId: this.userId,
        videoUrl: ossUrl,
        type: this.activityId ? 1 : 0,
        activity_id: this.activityId
      }


      if (this.fileType === 1) {
        params.recordingParams = this.validateRecordingParams()
        params.cameraIntrinsicParameters = this.validateCameraParams()
      }


      await ActivityServices.uploadData(params)
    },


    // 参数校验方法
    validateRecordingParams() {
      const requiredFields = [
        'recordType', 'sceneType', 'quality', 
        'players', 'startTime', 'endTime'
      ]
      
      requiredFields.forEach(field => {
        if (!this.recordingParams?.[field]) {
          throw new Error(`缺少必要录制参数: ${field}`)
        }
      })


      return {
        ...this.recordingParams,
        startTime: new Date(this.recordingParams.startTime).getTime(),
        endTime: new Date(this.recordingParams.endTime).getTime()
      }
    },


    validateCameraParams() {
      const requiredFields = [
        'focalLength', 'principalPoint', 'sensorSize',
        'distortionCoefficients', 'deviceModel'
      ]


      requiredFields.forEach(field => {
        if (!this.cameraParams?.[field]) {
          throw new Error(`缺少必要相机参数: ${field}`)
        }
      })


      return this.cameraParams
    }
  }
}
</script>
回答关注问题邀请回答
收藏

2 个回答

  • showms
    showms
    08-04

    上传文件的接口域名是写在upload域名中

    请求获取数据的接口域名才是写在request域名中

    08-04
    有用
    回复
  • sun
    sun
    发表于小程序端
    08-03

    上传文件,需要配置到uploadfile域名里

    08-03
    有用
    回复
登录 后发表内容