vue 上传文件到华为云obs
有两种方式, 第一种是在前端直接上传文件到obs, 第二种是先把文件上传到后台, 然后后台再调用obs对应开发语言的SDK
1. 前端直接上传文件到obs,不经过后端
1.1 使用npm引入包
// 安装 npm i esdk-obs-browserjs
// 引入 import * as ObsClient from 'esdk-obs-browserjs'
1.2 上传方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | uploadObs() { // 创建ObsClient实例 var obsClient = new ObsClient({ access_key_id: 'xxx' , // 你的ak secret_access_key: 'xxx' , // 你的sk server: 'https://xxx.com' // 你的endPoint }) obsClient.putObject({ Bucket: 'xxx' , // 桶名 Key: this .path + 'test01.jpg' , // 路径 + 文件名 SourceFile: document.getElementById( 'input-file' ).files[0] }, function (err, result) { if (err) { console.error( 'Error-->' + err) } else { console.log( 'Status-->' + result.CommonMsg.Status) } }) }, |
new ObsClient时报错
Error in v-on handler: "TypeError: _huaweiobs_esdk_obs_browserjs_3_22_3_min_
解决办法:
页面的import改为:
import ObsClient from 'esdk-obs-browserjs/src/obs'
此时如果报以下错误
Access to XMLHttpRequest at 'https://xxx.obs.cn-north-4.myhuaweicloud.com/?apiversion' from origin 'http://localhost:8080' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
则是跨域问题
解决办法:
配置桶的CORS
- 登录OBS Console后在桶列表中,单击待操作的桶,进入“概览”页面;
- 在“基础配置”下,单击“CORS规则”卡片,进入“CORS规则”界面,如下图所示:
- 在“CORS规则”界面,单击“创建”,系统弹出“创建CORS规则”对话框,在该对话框中按照上表的参数进行配置,如下图所示:
- 单击“确定”,并在“CORS规则”界面查看已配置好的规则
说明:
桶的CORS配置会在两分钟内生效,生效后才能使用OBS BrowserJS SDK访问桶。
参考官方文档: 配置桶的CORS_对象存储服务 OBS_BrowserJS_初始化_华为云
如果是使用element-ui的el-upload上传组件,则定义:http-request属性即可
1.3 获取上传进度
同时SDK提供获取上传进度的回调 ProgressCallback
示例代码:
// 创建ObsClient实例 var obsClient = new ObsClient({ access_key_id: '*** Provide your Access Key ***', secret_access_key: '*** Provide your Secret Key ***', server : 'https://your-endpoint' }); var callback = function(transferredAmount, totalAmount, totalSeconds){ // 获取上传平均速率(KB/S) console.log(transferredAmount * 1.0 / totalSeconds / 1024); // 获取上传进度百分比 console.log(transferredAmount * 100.0 / totalAmount); // 百分比取整数 console.log(Math.floor(transferredAmount * 100.0 / totalAmount)) }; obsClient.putObject({ Bucket : 'bucketname', Key : 'objectname', SourceFile : document.getElementById('input-file').files[0], ProgressCallback: callback }, function (err, result) { if(err){ console.error('Error-->' + err); }else{ console.log('Status-->' + result.CommonMsg.Status); } });
配合element-ui的el-progress组件, 即可显示上传进度
参考官方文档: 获取上传进度_对象存储服务 OBS_BrowserJS_上传对象_华为云
1.4 文件访问地址
browserjs的sdk在上传的回调中没有返回文件访问地址, 所以我们可以自己进行拼接
'https://' + bucket + '.obs.cn-north-4.myhuaweicloud.com/' + key
bucket是桶名, bucket后面的字符串是 endPoint, 一般endPoint是
https://obs.cn-north-4.myhuaweicloud.com
2. 先上传到后端,然后再上传到obs
2.1 前端代码:
这里用的vue + element-ui
js:
// 文件上传成功后触发的函数 handleAvatarSuccess: function (res, file) { console.log('文件上传成功') console.log(res) this.dataItem.picture = res.data this.imageUrl = res.data console.log(res.data) }, // 文件上传失败后触发的函数 handleAvatarError: function (res, file) { if (res.errorCode) { this.$message.error(res.errorMsg) } else { this.$message.error('文件上传失败') } }, beforeAvatarUpload: function (file) { const isJPG = (file.type === 'image/jpg' || file.type === 'image/jpeg' || file.type === 'image/png') const isLt2M = file.size / 1024 / 1024 < 2 if (!isJPG) { this.$message.error('上传头像图片只能是 JPG 格式!') } if (!isLt2M) { this.$message.error('上传头像图片大小不能超过 2MB!') } return isJPG && isLt2M }, // 上传进度 uploadAvatarProcess(event, file, fileList) { this.videoFlag = true console.log(typeof (file.percentage.toFixed(0))) this.videoUploadPercent = Math.floor(event.percent) },
html:
<el-form-item label="图片:"> <el-upload class="avatar-uploader" :action="imgAction" :show-file-list="false" :on-success="handleAvatarSuccess" :on-error="handleAvatarError" :on-progress="uploadAvatarProcess" name='file' :data="imgpath" :before-upload="beforeAvatarUpload"> <img v-if="imageUrl" :src="imageUrl" class="avatar"> <i v-else class="el-icon-plus avatar-uploader-icon"></i> </el-upload> </el-form-item>
2.2 后端代码
这里后端用的是java, springboot框架
maven依赖:
<!-- 华为云obs --> <dependency> <groupId>com.huaweicloud</groupId> <artifactId>esdk-obs-java</artifactId> <!-- 下面的设置是为了获取最新obs的maven最新版本号, 但是新版本的okhttp3会和别的依赖冲突,所以就指定了一个不会冲突的版本 --> <!-- <version>[3.20.6.1,)</version>--> <version>3.20.6.1</version> </dependency>
后端上传接口代码:
/** * 上传文件到obs * * @param path 服务器端存储的路径 * @param file 服务器商存储的文件名称 * @return */ @ApiOperation(value = "上传文件到obs", notes = "上传文件到obs") @PostMapping(value = "/upload") @ResponseBody public Response upload(@ApiParam(name = "path", value = "obs存储路径") @RequestParam(value = "path") String path, @ApiParam(name = "file", value = "文件") @RequestParam(value = "file") MultipartFile file) { Long userId = httpServletRequest.getHeader(Constants.USER_ID) != null ? Long.parseLong(httpServletRequest.getHeader(Constants.USER_ID)) : 1L; LogGenerator.genLog( httpServletRequest, userId, LogConstants.HUA_WEI_CLOUD_OBS.UPLOAD, path ); System.out.println("正在请求 obs / upload 上传文件接口----------------"); System.out.println("文件大小: " + ByteUtils.byteFormatString(file.getSize())); long startTime = System.currentTimeMillis(); ObsClient obsClient; try { // 用UUID命名文件 String fileName = UUIDUtil.getUUID() + file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf(".")); // 服务器临时路径 String targetPath = imgpath + fileName; System.out.println("服务器图片路径: " + targetPath); File tempImg = new File(targetPath); // 先上传到服务器 file.transferTo(tempImg); String accountName = env.getProperty("HWObs.HWAccountName"); String name = env.getProperty("HWObs.HWUsername"); String password = env.getProperty("HWObs.HWPassword"); String projectName = env.getProperty("HWObs.HWProjectName"); String token = ObsUtils.getToken(accountName, name, password, projectName); if (token == null || token.length() <= 0) { return Response.failure("token解析错误"); } String result = ObsUtils.getSecurityToken(token); if (StringUtils.isBlank(result)) { return Response.failure("securityToken解析错误"); } CredentialDto credentialDto = JSONObject.parseObject(result, CredentialDto.class); if (credentialDto == null) { return Response.failure("securityToken返回值解析错误"); } String ak = credentialDto.getCredential().getAccess(); String sk = credentialDto.getCredential().getSecret(); String securitytoken = credentialDto.getCredential().getSecuritytoken(); // System.out.println("ak: " + ak); // System.out.println("sk: " + sk); // System.out.println("securitytoken: " + securitytoken); String endPoint = env.getProperty("HWObs.HWEndPoint"); // 创建ObsClient实例 obsClient = new ObsClient(ak, sk, securitytoken, endPoint); String bucketName = env.getProperty("HWObs.HWBucketName"); PutObjectResult putObjectResult = obsClient.putObject(bucketName, path + fileName, tempImg); // localfile为待上传的本地文件路径,需要指定到具体的文件名 if (putObjectResult == null) { return Response.failure("上传失败"); } System.out.println("上传obs成功: " + putObjectResult.getObjectUrl()); // 删除临时文件 boolean deleteResult = tempImg.delete(); System.out.println("临时文件删除结果: " + deleteResult); long endTime = System.currentTimeMillis(); System.out.println("耗时: " + ((endTime - startTime) / 1000) + "秒"); return new Response(putObjectResult.getObjectUrl()); } catch (Exception e) { e.printStackTrace(); } return Response.failure("上传失败"); }
结束
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 一个奇形怪状的面试题:Bean中的CHM要不要加volatile?
· [.NET]调用本地 Deepseek 模型
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· 全网最简单!3分钟用满血DeepSeek R1开发一款AI智能客服,零代码轻松接入微信、公众号、小程
· .NET 10 首个预览版发布,跨平台开发与性能全面提升
· 《HelloGitHub》第 107 期
· 从文本到图像:SSE 如何助力 AI 内容实时呈现?(Typescript篇)
· 全程使用 AI 从 0 到 1 写了个小工具