vue使用axio发送post请求上传文件(multipart/form-data)到后端
2025/4/23...大约 3 分钟
vue使用axio发送post请求上传文件(multipart/form-data)到后端
<template>
<el-drawer
:title="title"
:visible.sync="show"
:size="size"
:modal-append-to-body="false"
>
<el-form ref="form" :model="form" :rules="rules">
<el-row :gutter="20">
<el-col :md="24" :lg="24" :xl="24">
<el-form-item label="头像">
<el-upload
class="avatar-uploader"
action="#"
:show-file-list="false"
:before-upload="beforeAvatarUpload"
:http-request="uploadAvatar">
<img v-if="form.avatar" :src="form.avatar" class="avatar">
<i v-else class="el-icon-plus avatar-uploader-icon"></i>
</el-upload>
</el-form-item>
</el-col>
</el-row>
</el-form>
<div>
<el-button @click="cancel">关闭</el-button>
<el-button type="primary" @click="saveForm">保存</el-button>
</div>
</el-drawer>
</template>
<script>
import {uploadFile} from "@/api/global/oss.js";
export default {
name: "Setting",
components: {
},
props: {
visible: Boolean,
size: {
type: String,
default: 'default'
}
},
data() {
return {
title: "设置",
form: {
avatar: ''
},
rules: {}
};
},
mounted() {
const userInfo = this.$store.state.user.userInfo
if (userInfo) {
this.form.avatar = userInfo.avatar
}
},
computed: {
show: {
get() {
return this.visible;
},
set(val) {
this.$emit('update:visible', val);
}
}
},
methods: {
cancel() {
this.$emit('update:visible', false)
this.resetForm()
},
resetForm() {
this.$refs.form.resetFields()
},
beforeAvatarUpload(file) {
const isJPG = file.type === 'image/jpeg' || file.type === 'image/png'
const isLt2M = file.size / 1024 / 1024 < 2
if (!isJPG) {
this.$message.error('上传头像图片只能是 JPG/PNG 格式!')
}
if (!isLt2M) {
this.$message.error('上传头像图片大小不能超过 2MB!')
}
return isJPG && isLt2M
},
uploadAvatar(file) {
// 这里需要实现文件上传逻辑
// 上传成功后更新form.avatar
uploadFile(file.file).then(res => {
this.form.avatar = res.data.fileName
})
},
}
}
</script>
<style lang="scss" scoped>
.avatar-uploader {
border: 1px dashed #d9d9d9;
border-radius: 6px;
cursor: pointer;
position: relative;
overflow: hidden;
width: 178px;
height: 178px;
}
.avatar-uploader:hover {
border-color: #409EFF;
}
.avatar-uploader-icon {
font-size: 28px;
color: #8c939d;
width: 178px;
height: 178px;
line-height: 178px;
text-align: center;
}
.avatar {
width: 178px;
height: 178px;
display: block;
}
</style>
// @/api/global/oss.js 上传文件
export const uploadFile = (file) => {
let formData = new FormData()
formData.append('file', file)
return request({
url: serverName + '/oss/upload?project=projectName',
method: 'post',
headers: {
'Content-Type': 'multipart/form-data'
},
data: formData
})
}
后端代码,这里用的阿里云OSS
<dependency>
<groupId>com.aliyun.oss</groupId>
<artifactId>aliyun-sdk-oss</artifactId>
</dependency>
@PostMapping(value = "/upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public R<Map<String, String>> upload(@RequestParam(value="project",required = false,defaultValue = "") String project,@RequestPart("file") MultipartFile file) {
String fileName = ossComponent.ossUpload(project, file);
Map<String, String> map = new HashMap<>(2);
map.put("fileName", fileName);
return R.ok(map);
}
ossComponent.java 的 ossUpload 方法
private static final String CONTENT_DISPOSITION="inline";
@Override
public String ossUpload(String project,MultipartFile file) {
String uploadFile = "";
// 创建OSSClient实例。
OSS ossClient = new OSSClientBuilder().build(ossProperties.getEndpoint(), ossProperties.getAccessKeyId(), ossProperties.getAccessKeySecret());
try {
String fileName = getUploadFileName(project, FileUtil.getSuffix(file.getOriginalFilename()));
//设置header
ObjectMetadata metadata = new ObjectMetadata();
metadata.setContentDisposition(CONTENT_DISPOSITION);
metadata.setContentType(getcontentType("."+FileUtil.getSuffix(fileName)));
// 指定OSS创建目标Object时使用的服务器端加密算法。
metadata.setHeader(OSSHeaders.OSS_SERVER_SIDE_ENCRYPTION, ObjectMetadata.AES_256_SERVER_SIDE_ENCRYPTION);
// 创建PutObject请求。
PutObjectRequest putObjectRequest = new PutObjectRequest(ossProperties.getBucketName(), fileName, file.getInputStream());
putObjectRequest.setMetadata(metadata);
ossClient.putObject(putObjectRequest);
//返回全路径
uploadFile = ossProperties.getCdnUrl() + fileName;
}catch (Exception e) {
log.error(e.getMessage(),e);
}finally {
if (ossClient != null) {
ossClient.shutdown();
}
}
return uploadFile;
}
/**
* 获取文件名
* @param project 项目
* @param suffix 扩展名
* @return
*/
public static String getUploadFileName(String project, String suffix) {
String activeProfile = SpringUtils.getActiveProfile();
if(StringUtils.isEmpty(project)){
project = SpringUtils.getApplicationName();
}
StringBuilder sb = new StringBuilder(activeProfile).append("/").append(project).append("/")
.append(DateUtil.format(DateUtil.date(), "yyyy/MM/dd/"))
.append(String.format("%s%010d", DateUtil.format(DateUtil.date(), DatePattern.PURE_DATETIME_MS_FORMAT), lastId.incrementAndGet()))
.append(".").append(suffix);
return sb.toString();
}
/**
* 获取文件类型
* @param filenameExtension
* @return
*/
public static String getcontentType(String filenameExtension) {
if (filenameExtension.equalsIgnoreCase(".bmp")) {
return "image/bmp";
}
if (filenameExtension.equalsIgnoreCase(".gif")) {
return "image/gif";
}
if (filenameExtension.equalsIgnoreCase(".jpeg") ||
filenameExtension.equalsIgnoreCase(".jpg") ||
filenameExtension.equalsIgnoreCase(".png")) {
return "image/jpg";
}
if (filenameExtension.equalsIgnoreCase(".html")) {
return "text/html";
}
if (filenameExtension.equalsIgnoreCase(".txt")) {
return "text/plain";
}
if (filenameExtension.equalsIgnoreCase(".vsd")) {
return "application/vnd.visio";
}
if (filenameExtension.equalsIgnoreCase(".pptx") ||
filenameExtension.equalsIgnoreCase(".ppt")) {
return "application/vnd.ms-powerpoint";
}
if (filenameExtension.equalsIgnoreCase(".docx") ||
filenameExtension.equalsIgnoreCase(".doc")) {
return "application/msword";
}
if (filenameExtension.equalsIgnoreCase(".xml")) {
return "text/xml";
}
if (filenameExtension.equalsIgnoreCase(".pdf")) {
return "application/pdf";
}
if (filenameExtension.equalsIgnoreCase(".xls")) {
return "application/vnd.ms-excel";
}
if (filenameExtension.equalsIgnoreCase(".xlsx")) {
return "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
}
if (filenameExtension.equalsIgnoreCase(".doc")) {
return "application/msword";
}
if (filenameExtension.equalsIgnoreCase(".docx")) {
return "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
}
if (filenameExtension.equalsIgnoreCase(".zip")) {
return "application/zip";
}
if (filenameExtension.equalsIgnoreCase(".mp4")) {
return "video/mp4";
}
return "image/jpg";
}
参考文章 文章中提到我的方法后端会提示500,the request was rejected because no multipart boundary was found 我这里没有出现这问题,有出现这问题可以参考