taro + react hooks + oss小程序上传

2022-11-16  本文已影响0人  月光一族

最近在做一个新项目,用到了taro + react hooks + oss小程序上传。今天就来分享一下其中的技术,目前来看,taro+ react hooks做的小程序很多框架不兼容,尤其是UI框架,能够打包成功的很少。试了只有@nutui/nutui-react-taro 和 taro-ui@3.1.0-beta.2在小程序执行时打包成功,当然了,小程序只需要在微信开发者工具上传即可,不需要打包,之前在这里的纠结的原因是习惯了build,尴尬了。

1、按照taro官方文档构建一个新项目,config配置添加别名配置如下:

alias: {

'@': path.resolve(__dirname, '..', 'src'),

  '@/images': path.resolve(__dirname, '..', 'src/images'),

  '@/assets': path.resolve(__dirname, '..', 'src/assets'),

  '@/components': path.resolve(__dirname, '..', 'src/components'),

  //'@/constants': path.resolve(__dirname, '..', 'src/constants'),

//'@/reducers': path.resolve(__dirname, '..', 'src/reducers'),

  '@/common': path.resolve(__dirname, '..', 'src/common'),

  '@/utils': path.resolve(__dirname, '..', 'src/utils')

},

2、把需要调用的api封装在src/api

import { toQueryString }from '@/utils/filter'

import service from '@/utils/request';

//特殊请求加上这段编码

const otherHeader = {'Content-Type':'application/x-www-form-urlencoded', 'Accept':'*/*' }

//获取oss的信息

export const ossGetAccessUrl = (params, headers) => {

return service({

method:'GET',

    url:'/oss/token',

    data: params,

    headers: headers

})

}

3、把全局主题色封装在common/theme.scss下

@charset "UTF-8";

//默认全局背景主题色!default

$default-background:#F6F6F7;

//默认字体、按钮背景主题色

$default-primary:#52A86A;

4、把全局组件封装在components下

5、把需要过滤的封装在utils/filter下

// 将一个对象转成QueryString

export const toQueryString = (obj) => {

if (!obj)return "";

    return cleanArray(

Object.keys(obj).map(key => {

if (obj[key] ===undefined)return "";

            return encodeURIComponent(key) +"=" +encodeURIComponent(obj[key]);

        })

).join("&");

}

6、把请求拦截封装在utils/request

import Taro from '@tarojs/taro'

const baseURL ='https://xxx.xxx.com/'

let token ='xxxxxxxx'

let flag =true;

export const service = (parmas) => {

parmas.headers['token'] = token;

  let result =new Promise((resolve, reject) => {

Taro.request({

url: baseURL + parmas.url, 

      data: parmas.parmas,

      method:parmas.method ,

      header: {

...{

'content-type':'application/json' // 默认值

        }, ...parmas.headers

      },

      success:function (response) {

if (response.statusCode && response.statusCode !==200) {

if (flag) {

Taro.showToast({

title:JSON.stringify(response.data.message),

              icon:'none'

            })

flag =false;

            setTimeout(() => {

flag =true;

            }, 1000)

}

}

if (response.statusCode ===200) {

resolve(response.data)

}else {

reject();

        }

},

      fail(e:any) {

let message ="";

        switch (e.status) {

case 400:

message ="请求错误";

break;

          case 401: {

message ="未授权,请登录";

break;

          }

case 403:

message ="没有权限,拒绝访问";

break;

          case 404:

message =`请求地址出错`;

break;

          case 500:

message ="服务器内部错误";

break;

          case 501:

message ="服务未实现";

break;

          case 502:

message ="网关错误";

break;

          case 503:

message ="服务不可用";

break;

          case 504:

message ="网关超时";

break;

          case 505:

message ="HTTP版本不受支持";

break;

          default:

break;

        }

if (flag) {

Taro.showToast({

title: message,

            icon:'none'

          })

flag =false;

          setTimeout(() => {

flag =true;

          }, 1000)

}

reject(e)

}

})

})

return result;

}

下面来讲封装小程序上传图片到oss,因为小程序上传的图片与h5或web端不一样,没有file的概念,就需要看阿里云文档踩坑

1、封装stsToken,需要通过加密等方式得到signature,policy,x-oss-security-token

import cryptofrom 'crypto-js';

import {Base64}from 'js-base64';

// 计算签名。

function computeSignature(accessKeySecret, canonicalString) {

return crypto.enc.Base64.stringify(crypto.HmacSHA1(canonicalString, accessKeySecret));

}

const date =new Date();

date.setHours(date.getHours() +1);

const policyText = {

expiration: date.toISOString(), // 设置policy过期时间。

  conditions: [

// 限制上传大小。

    ["content-length-range", 0, 1024 *1024 *1024],

  ],

};

export const getFormDataParams =async (credentials) => {

const policy = Base64.encode(JSON.stringify(policyText))// policy必须为base64的string。

  const signature =computeSignature(credentials.AccessKeySecret, policy)

const formData = {

OSSAccessKeyId: credentials.AccessKeyId,

    signature,

    policy,

    'x-oss-security-token': credentials.SecurityToken

  }

return formData

}

2、封装Taro.uploadFile上传方法,传入host、signature、OSSAccessKeyId、policy、key、filePath

import Taro from "@tarojs/taro";

export const wxUpload = (data) => {

const host = data.host;

  const signature = data.signature;

  const ossAccessKeyId = data.OSSAccessKeyId;

  const policy = data.policy;

  const key = data.key;

  const securityToken = data['x-oss-security-token'];

  const filePath = data.filePath; // 待上传文件的文件路径。

  let result =new Promise((resolve, reject) => {

Taro.uploadFile({

url: host, // 开发者服务器的URL。

      filePath: filePath,

      name:'file', // 必须填file。

      formData: {

name: filePath,

        key,

        policy,

        OSSAccessKeyId: ossAccessKeyId,

        signature,

        success_action_status:"200",

        'x-oss-security-token': securityToken// 使用STS签名时必传。

      },

      success: (res) => {

console.log(res)

if (res.statusCode ===200) {

Taro.showToast({title:'上传成功', icon:'none'})

resolve(host +'/' + key);

        }

},

      fail: err => {

reject(null)

Taro.showToast({title:'上传失败', icon:'none'})

return null;

      }

});

  })

return result;

}

3、封装osstoken获取以及图片上传调用,在选完图片后会调用一次ossGetAccessUrl,可优化为进入首页调用,放在dva中缓存起来ossGetAccessUrl,考虑到oss的token可能会失效,所以我这里每次上传都调用一次

import {randomString, filterUTCNo}from './filter'

import OSS from 'ali-oss';

import Taro from "@tarojs/taro";

import {getFormDataParams}from './sts'

import {wxUpload}from './wxUpload'

import {ossGetAccessUrl}from '@/api/home'

class MyUploadAdapterAll {

constructor(params) {

// 要在上载期间使用的文件加载器实例

    this.file = params.file

    this.ossGetAccessUrlData = {}

}

async getAccessUrl() {

if (!this.file) {

return

    }

try {

Taro.showLoading()

let res =await ossGetAccessUrl({}, {})

Taro.hideLoading()

if (res.code ===200) {

        let dataParams:any =await getFormDataParams({

AccessKeySecret: res.data.accessKeySecret,

          AccessKeyId: res.data.accessKeyId,

          SecurityToken: res.data.securityToken,

        })

dataParams.key =`${filterUTCNo(new Date())}/${randomString(8)}_${Date.now()}.${this.file.split('.')[this.file.split('.').length -1]}`

        dataParams.host ='https://' + res.data.bucket +'.' + res.data.endPoint.split('//')[1];

        dataParams.filePath =this.file;

        console.log(dataParams)

return await wxUpload(dataParams);

      }

}catch (e) {

      console.log(e)

}

}

}

export default MyUploadAdapterAll

4、在页面中引入调用

import MyUploadAdapterAllfrom "@/utils/uploadAll";

Taro.chooseImage({

count:1, // 默认9

  sizeType: ['original', 'compressed'], // 可以指定是原图还是压缩图,默认二者都有

  sourceType: ['album', 'camera'], // 可以指定来源是相册还是相机,默认二者都有,在H5浏览器端支持使用 `user` 和 `environment`分别指定为前后摄像头

  success:async (res) => {

console.log(res)

const myUploadAdapter =new MyUploadAdapterAll({

dir:'dev',

      file: res.tempFilePaths[0]

})

let url:string =await myUploadAdapter.getAccessUrl()

if (url) {

console.log(url)

}

}

})

上一篇下一篇

猜你喜欢

热点阅读