> For AI agents: the complete documentation index is available at /llms.txt, the full documentation bundle is available at /llms-full.txt.

# OSS 上传「PUT」

## 场景需求

最初上传文件是借助后台 **API** 来实现文件的存储，相对现在主流的 **OSS** 直传来说，还是比较繁琐的。之前介绍的文件上传是基于 **OSS** 直传的 **POST** 方式实现的，需要借助 **FormData** 来实现文件的上传，相关代码案例请参考我之前写的文章 [iView OSS 直传](/blog/upload/oss-direct-upload.md)。

此次是借助阿里云提供的 [**ali-oss**](https://github.com/ali-sdk/ali-oss) 来实现文件上传，此方法还支持大文件大断点续传，如有需要请参考 **OSS** 云存储官方提供的[**文档 API**](https://help.aliyun.com/document_detail/64041.html?spm=a2c4g.11174283.6.1222.13e57da2QgjZ2o)。**OSS** 的 **PUT** 上传方式支持异步上传和同步上传，上传成功后直接返回上传文件在阿里云云存储上的绝对路径；之前的 **POST** 上传方式是将文件对象转换成 **FormData** 对象来上传的，其返回的是上传文件的相对路径，若想获取文件在云存储上的绝对路径，还需要自己进行手动拼接，相比较 **PUT** 上传方式来说比较麻烦，而且还容易出错。

## 前期处理

首先要根据自己的实际情况来选择符合自己的 **OSS** 文件上传方式。此次我主要就 **OSS** 的 **PUT** 文件上传方式做介绍。
先登录阿里云 **OSS** 云存储的管理后台，进入自己索要配置的 **bucket** 类型，然后查找**配置跨域资源共享（CORS）规则** ,来对该 **bucket** 的跨域资源共享规则按照官方文档给的要求来进行相应的设置。

:::info 图例
![文件上传](/static/image/4-1.39bdee7b02.jpg)
注：

- **此页面为配置跨域规则的页面，请确认**已勾选 PUT\*\*请求方式。
- 若没勾选此方式，当采用 PUT 方式上传文件时，控制台会报请求**跨域**错误。

:::

## 代码案例

- **安装所需依赖**

```javascript title="安装"
/* 时间处理工具 */
import dayjs from "dayjs";
/* 阿里云OSS文件直传工具 */
import OSS from "ali-oss";
/* 基于VUE的前端UI框架 */
import { ElMessage } from "element-plus";
```

**注意：**

- [**dayjs**](https://dayjs.fenxianglu.cn/category/) 在后续处理文件路径和文件重命名时需用到，若无需文件重命名则不用安装；
- [**element-plus**](https://element-plus.gitee.io/#/zh-CN/component/installation) 为基于 **Vue3** 的 **ElementUI** 升级版，此处主要用于文件上传时候相关校验的提示；
- **文件重命名**

```javascript title="文件重命名"
const fileRename = (file, rootPath = "", fileType = [], size = 0) => {
    /* 判断传过来的值是否为file对象 */
    if (!(file instanceof Object)) return null;
    // 文件大小限制
    if (size && file.size >= size * 1024 * 1024) {
        ElMessage.warning(`上传的文件大小不能超过 ${size}M，请重新上传！`);
        return null;
    }
    // 将文件名字做英文字符小写处理，为了方便判断上传文件的格式
    let fileName = file.name.toLowerCase(),
        dotIndex = fileName.lastIndexOf("."),
        // 获取文件后缀名
        fileSuffix = fileName.substr(dotIndex);
    // 传过来的用于判断文件类型的数组，拼接成字符串
    let fileTypeString = fileType.join(".");
    // 文件类型限制
    if (fileTypeString && !fileTypeString.includes(fileSuffix)) {
        ElMessage.error("上传文件类型有误，请重新上传！");
        return null;
    }
    /**
     * 文件路径处理
     * 基于dayjs来分配文件路径和对文件进行重命名
     *  */
    let filePath = dayjs().format("YYYY_MM/DD_HHmmss_SSS");
    // 返回文件在OSS上的相对文件路径
    return rootPath + filePath + fileSuffix;
};
```

**文件重命名参数介绍：**

- **file**：文件对象；

- **rootPath**：文件根路径即在 OSS 存储的根目录；

- **fileType**：要校验的文件类型格式；

- **size**：上传文件的大小限制。

- **OSS 文件上传**

```javascript title="文件上传"
/**
 * @module 文件上传
 * @param {Object} file - 文件对象
 * @param {String} rootPath - 文件根路径
 * @param {Array} fileType - 文件类型
 * @param {Number} size - 文件大小
 * @returns {String} - 上传文件地址
 **/
const OSSUpload = async (file, rootPath, fileType, size) => {
    // 调用fileRename生成的文件相对路径格式：xxxx.png，必须带后缀名，否则无法读取上传后的文件
    let fileName = fileRename(file, rootPath, fileType, size);
    if (!fileName) return null;
    // *配置client-OSS
    let client = new OSS({
        accessKeyId: "your access key" /* 通过阿里云控制台创建的access key */,
        accessKeySecret:
            "your access secret" /* 通过阿里云控制台创建的access secret */,
        region: "oss-cn-beijing" /* bucket 所在的区域 */,
        stsToken: "" /* 鉴权，sts方式需要使用，若不需要请删除或注释掉 */,
        bucket: "your bucket name" /* 通过控制台创建的bucket，【OSS文件前缀】 */,
    });

    try {
        /**
         * OSS的put直传
         * fileName：文件名【带后缀名】
         * file：文件对象
         *  */
        // File 对象
        let { res, url } = await client.put(fileName, file);
        // Blob 对象
        // let { res, url } = await client.put(fileName, new Blob(file));
        // OSS Buffer 对象
        // let { res, url } = await client.put(fileName, new OSS.Buffer(file));

        if (res.status == 200) {
            ElMessage.success("上传成功");
            return url;
        }
        ElMessage.error("上传失败");
        return null;
    } catch (e) {
        ElMessage.error("文件上传失败");
        return null;
    }
};
```

:::tip 注意事项

- 多行注释处请留心配置，否则会报错。**OSS.JS** 附件已上传，下载后配置好 **OSS** 相关参数就可直接使用。
- **OSS** 的 **PUT** 上传方式第二参数即 **file**，支持 **File 对象**、**Blob 数据** 以及 **OSS Buffer** 等格式。

:::

- **OSS 直传使用**

```javascript title="OSS 直传"
// 导入封装的OSS插件
import oss from "./oss.js";

/**
 * @param {Object} file - 文件对象
 * @param {String} rootPath - 文件根路径（默认为空、例：“filepath/”）
 * @param {Array} fileType - 文件类型限制（默认 [] 不限制，例：['.png','.jpeg']）
 * @param {Number} size - 文件大小限制（单位：兆、默认 0 不限制、例：1）
 **/
//获取到上传文件后调用OSS直传
// 方式一：
oss(file, "", [], 0).then((ossUrl) => {
    if (!!ossUrl) {
        // 上传成功，返回上传后的绝对路径
    } else {
        // 上传失败，返回null
    }
});
// 方式二：不做任何限制时，参数可省略
oss(file).then((ossUrl) => !!ossUrl && (uploadURL = ossUrl));
```

## 结语

🥇🥈🥉：前期努力搬的砖，都是为后期造轮子准备的。若对您有所帮助，请帮忙点个赞 👍！
