做网站不买服务器百度能搜到,网站做友情链接,做一个二手网站怎么做,电商平台搭建方案最近在做移动端app#xff0c;开始接触uniapp。想着直接用PC端的前后端API去做文件上传#xff0c;但是uniapp的底层把请求拆成了普通请求和文件上传请求#xff0c;所以不能用一个axios去做所有请求的处理#xff0c;拆成uni.request和uni.uploadFile去分别处理两种情况。… 最近在做移动端app开始接触uniapp。想着直接用PC端的前后端API去做文件上传但是uniapp的底层把请求拆成了普通请求和文件上传请求所以不能用一个axios去做所有请求的处理拆成uni.request和uni.uploadFile去分别处理两种情况。
H5 所以要封装两个请求接口一个request.js普通请求封装和PC大致相同。另一个是文件请求封装 用upload.js去封装uni.uploadFile做请求拦截器
import store from /store;
import config from /config;
import { getToken } from /utils/auth;
import errorCode from /utils/errorCode;
import { toast, showConfirm, tansParams } from /utils/common;let timeout 10000;
const baseUrl config.baseUrl;const upload (config) {// 是否需要设置 tokenconst isToken (config.headers || {}).isToken false;config.header config.header || {};if (getToken() !isToken) {config.header[Authorization] getToken();}// get请求映射params参数if (config.params) {let url config.url ? tansParams(config.params);url url.slice(0, -1);config.url url;}return new Promise((resolve, reject) {uni.uploadFile({timeout: config.timeout || timeout,url: baseUrl config.url,filePath: config.filePath,name: config.name || file,header: config.header,formData: config.formData,success: (res) {let result JSON.parse(res.data);const code result.code || 200;const msg errorCode[code] || result.msg || errorCode[default];if (code 200) {resolve(result);} else if (code 401) {showConfirm(登录状态已过期您可以继续留在该页面或者重新登录?).then((res) {if (res.confirm) {store.dispatch(LogOut).then((res) {uni.reLaunch({ url: /pages/login/login });});}});reject(无效的会话或者会话已过期请重新登录。);} else if (code 500) {toast(msg);reject(500);} else if (code ! 200) {toast(msg);reject(code);}},fail: (error) {let { message } error;if (message Network Error) {message 后端接口连接异常;} else if (message.includes(timeout)) {message 系统接口请求超时;} else if (message.includes(Request failed with status code)) {message 系统接口 message.substr(message.length - 3) 异常;}toast(message);reject(error);},});});
};export default upload;然后修改之前的前端API为
import upload from /utils/upload;export function fileUpload(data) {return upload({url: /common/app/upload/ data.fileType,name: data.name,filePath: data.filePath,});
} 这里api解释一下因为现在uniapp上传文件接口的差别是创建一个临时url我们去上传这个临时文件url到后端去保存的。 所以前后端的接口都需要做调整后端是拿到前端的文件然后转存到指定位置再传回文件的路径。
后端API PostMapping(/app/upload/{fileType})public R appUpload(MultipartFile file,PathVariable String fileType) {// 检查文件是否存在if (file.isEmpty()) {log.info(文件不存在请检查路径);throw new CustomException(文件上传失败);}String fileFolder basePath File.separator file;if (File.separator.equals(\\)) {// 本地windows测试fileFolder C:\\Users\\A\\Desktop\\rm-mes\\data\\file;}File imgFolder new File(fileFolder);if (!imgFolder.exists()) {imgFolder.mkdirs();log.info(创建指定目录文件夹 fileFolder);}// 获取文件大小字节long fileSize file.getSize();// 转换为MBdouble fileSizeInMB fileSize / (1024.0 * 1024.0); // 使用1024.0确保结果为浮点数// UUID重新生成文件防止重复覆盖String fileName UUID.randomUUID() . fileType;// xxx.jpg xxx.mp4String filePath fileFolder File.separator fileName;try {// 文件转存位置file.transferTo(new File(filePath));} catch (IOException e) {e.printStackTrace();}return R.ok().data(filePath, filePath).data(fileType, fileType).data(fileSize, fileSizeInMB);} 文件的后缀是通过前端传过来的类型去保存的按照之前PC端动态获取文件后缀的方式会失败导致 然后到前端的签名图片上传 async uploadSignature() {const blob this.base64ToBlob(this.signature);const filePath URL.createObjectURL(blob); // 创建一个临时的文件路径let data { name: file, filePath: filePath, fileType: png };const res await fileUpload(data);this.editForm.responsibleSign res.data.filePath;},base64ToBlob(b64) {const byteCharacters atob(b64.replace(data:image/png;base64,, )); // 把前缀去掉const byteNumbers new Array(byteCharacters.length);for (let i 0; i byteCharacters.length; i) {byteNumbers[i] byteCharacters.charCodeAt(i);}const byteArray new Uint8Array(byteNumbers);const blob new Blob([byteArray], { type: image/jpeg });return blob;}, 在我们签完名后一般会拿到签名的base64编码现在要根据接口的需求创建一个临时URL放到请求中所以第一步先调用base64ToBlob转成Blob后再创建临时地址。最后创建请求体的数据把文件的路径和文件类型即可最后调用接口保存到服务器中~ uniApp 如果不是H5的环境下上传文件会比较麻烦需要考虑是app还是哪个第三方的小程序。因为在app中创建临时文件需要获取当前运行环境还要获取一些设备权限。 所以想要避免这种前端差异和麻烦我们把后端文件上传接口改成接收base64编码在后端去转码成文件保存到服务器中。那么现在我们在前端需要写一个base64编码转换的方法。如果能直接拿到则跳过直接调用请求api即可。 现在不在H5环境下签名会拿到一个图片的临时地址但是这个地址不能通过第一种创建Blob方式临时http的形式传到后端。因为app不支持http的创建。下面写个方法去转码
export function pathToBase64(path) {return new Promise(function (resolve, reject) {// appif (typeof plus object) {plus.io.resolveLocalFileSystemURL(path,function (entry) {entry.file(function (file) {var fileReader new plus.io.FileReader();fileReader.onload function (evt) {resolve(evt.target.result);};fileReader.onerror function (error) {reject(error);};fileReader.readAsDataURL(file);},function (error) {reject(error);});},function (error) {reject(error);});return;}// 微信小程序if (typeof wx object wx.canIUse(getFileSystemManager)) {wx.getFileSystemManager().readFile({filePath: path,encoding: base64,success: function (res) {resolve(data:image/png;base64, res.data);},fail: function (error) {reject(error);},});return;}reject(new Error(not support));});
}现在我们拿到base64编码那么其实就是一个字符串我们不需要使用uni.uploadFile(),直接用uni.request()去上传当做普通请求去处理放到post请求的请求体中即可。
修改前端api
import upload from /utils/upload;
import request from /utils/request;export function fileUpload(data) {return request({url: /common/app/upload,method: post,data: data,});
}修改后端api用png图片做示例 PostMapping(/app/upload)public R uploadBase64(RequestBody FlierInfo flierInfo) {String base64 flierInfo.getBase64();// 确定文件类型String fileType png;// 去掉前缀String base64Image base64.replace(data:image/png;base64,, );String fileFolder basePath File.separator file;if (File.separator.equals(\\)) {// 本地windows测试fileFolder C:\\Users\\A\\Desktop\\rm-mes\\data\\file;}File imgFolder new File(fileFolder);if (!imgFolder.exists()) {imgFolder.mkdirs();log.info(创建指定目录文件夹 fileFolder);}// UUID重新生成文件防止重复覆盖String fileName UUID.randomUUID() . fileType;// xxx.jpg xxx.mp4String filePath fileFolder File.separator fileName;Base64Util.GenerateImage(base64Image, filePath); // 转码成图片保存到指定路径return R.ok().data(filePath, filePath).data(fileType, fileType).data(fileSize, );}
前端调用
import { fileUpload } from /api/mes/system/common;
import { pathToBase64 } from /utils/pathToBase64;async submit(ref) {// await this.uploadSignature();pathToBase64(this.signature).then(async (base64) {// 保存base64图片await this.uploadSign(base64);}).catch((error) {console.error(error);});},
async uploadSign(base64) {let data {base64: base64,};const res await fileUpload(data);this.editForm.responsibleSign res.data.filePath;}, H5和app的处理文件上传的记录到此第一种方法在H5环境下拿到的base64编码其实可以直接发送到第二种情况的后端接口去做保存万变不离其宗。