还不会文件上传?React+Node.js前后端上传文件至阿里云OSS全过程

开头

最近在做自己的项目,项目中有上传图片头像的功能,以前的时候我的图片都是存在后端的,如果把图片进行base64转码后存在后端数据库的话,数据库说不定就爆了,前段时间我了解到可以把图片存在云服务器上,经过我的多方学习,终于是搞完了全过程。

开发使用的是React函数式组件配合Antd组件库,然后后端是Node.jsexpress框架。

前端

我这里使用的是Antd的Upload组件,然后使用customRequest实现自定义上传逻辑,这边主要是为了配合项目封装的axios,如果不使用自定义上传逻辑,使用它自带的上传功能的话,封装的axios以及token相关的设置都要重新搞。

js 复制代码
 <Upload
            name="avatar"
            listType="picture-circle"
            maxCount={1}
            className="avatar-uploader"
            showUploadList={false}
            accept=".jpg,.png"
            customRequest={handleUpload}
            >
            <img src={avatar} alt="" className="avatar-img" />
            <div className="avatar-tip">
                <span>点击上传头像</span>
            </div>
        </Upload>

关于Upload的相关属性可以直接去antd的官网查看,这边主要是自定义方法的阐述。

使用Upload组件选中文件点击确定,随后触发customRequest调用handleUpload方法,他接收一个参数对象如下:

js 复制代码
{
    "action": "",
    "filename": "avatar",
    "data": {},
    "file": File
        {
            uid: "rc-upload-1717379196249-2"
            lastModified: 1652845511820
            lastModifiedDate: Wed May 18 2022 11:45:11 GMT+0800 (中国标准时间) {}
            name: "UZBQRSR[5B@P~8)`7~B$VQK.jpg"
            size: 359734
            type: "image/jpeg"
            webkitRelativePath: "",
        }
    "headers": {},
    "withCredentials": false,
    "method": "post"
}

我们主要关注的是对象里File类型的文件,随后在handleUpload里定义一个formdata,并使用append方法把文件添加进去,随后调用接口将文件传到后端。

js 复制代码
    const handleUpload = async file => {
            const form = new FormData()
            form.append('file', file.file)
            const res = await uploadAvatar(form)
            setAvatar(res.avatar)
        }

接口这里要注意,需要定义请求头为application/x-www-form-urlencoded; charset=UTF-8,不然后端是收不到文件格式的文件的。

js 复制代码
export const uploadAvatar = formData => {
    return request.post('/users/info/avatar', formData, {
        headers: {
            // 上传文件需要改请求头
            'content-type': 'application/x-www-form-urlencoded; charset=UTF-8',
        },
    })
}

完整代码

js 复制代码
// 组件.js:
import React, { useState, useEffect } from 'react'
import { uploadAvatar } from '@/apis/account'
import { Input, Upload } from 'antd'

const Comp = () =>{
    const [avatar, setAvatar] = useState('')

    // 自定义上传逻辑的方法
    const handleUpload = async file => {
            const form = new FormData()
            form.append('file', file.file)
            const res = await uploadAvatar(form)
            setAvatar(res.avatar)
        }
    
        return (
        <Upload
            name="avatar"
            listType="picture-circle"
            maxCount={1}
            className="avatar-uploader"
            showUploadList={false}
            accept=".jpg,.png"
            customRequest={handleUpload}
            >
            <img src={avatar} alt="" className="avatar-img" />
            <div className="avatar-tip">
                <span>点击上传头像</span>
            </div>
        </Upload>
    )
}
// 接口.js:
export const uploadAvatar = formData => {
    return request.post('/users/info/avatar', formData, {
        headers: {
            // 上传文件需要改请求头
            'content-type': 'application/x-www-form-urlencoded; charset=UTF-8',
        },
    })
}

后端

现在文件已经通过请求传到后端了,后端首先需要一个中间件multer用来解析请求中的文件:.any()方法表示接受任意数量的上传字段,并将上传的文件信息存储在 req.files

js 复制代码
const multer = require('multer') //处理文件上传的中间件
const upload = multer()
router.use(upload.any())

解析后获取的文件格式如下:

js 复制代码
{
  originalname: 'UZBQRSR[5B@P~8)`7~B$VQK.jpg',
  encoding: '7bit',
  mimetype: 'image/jpeg',
  buffer: <Buffer ff d8 ff e1 00 8e 45 78 69 66 00 00 4d 4d 00 2a 00 00 00 08 00 05 01 00 00 03 00 00 00 01 00 00 00 00 0 00 01 01 00 03 00 00 00 01 00 00 00 00 87 69 00 04 ... 359684 more bytes>,
  size: 359734
}

随后写接口:从req.files[0]里拿到传过来的文件,随后调用阿里云的上传函数,将文件上传到阿里云OSS,uploadServer方法的第一个参数是文件的名字,可以自己是设置,第二个参数是文件的buffer属性,文件数据的缓冲区,是一个 Buffer 对象,包含了文件的实际内容,我们要上传的就是这个,阿里云上传完成后会拿到一个result对象,随后就是拿到阿里云返回的url保存到数据库以及返回到前端。

js 复制代码
router.post('/api/users/info/avatar', async (req, res) => {
    const file = req.files[0]
    //上传到阿里云OSS
    const result = await uploadServer(
        'avatar-' + req.data.uid + '-' + Date.now() + '.jpg',
        file.buffer
    )
    await User.updateOne({ uid: req.data.uid }, { $set: { avatar: result.url } }).catch(err => {
        console.log(err)
    })
    res.status(200).send({
        msg: '头像修改成功',
        code: 2000,
        data: {
            avatar: result.url,
        },
    })
})

阿里云OSS

官网操作步骤如下

  1. 前往阿里云官网,点击右上角注册一个账号。
  2. 搜索OSS,点击搜索结果中的对象存储OSS,点击购买。
  3. 看需求购买,我是买的最便宜的OSS资源包+标准-本地冗余存储+40G+6个月,才4米。
  4. 点击右上角控制台,在我的资源里找到对象存储OSS点进去。
  5. 点击左侧Bucket列表,随后创建Bucket,填写名称地区,我是开启公共读写,这个看需求。
  6. Hover头像点击AccessKey管理,创建AccessKey随后保存好(待会要用)

这样OSS存储服务器就弄好了。

代码

接下来编写之前用到的上传服务器的代码: 定义一个ali-oss.js,剩下的看注释就好了。

js 复制代码
const OSS = require('ali-oss')

const client = new OSS({
    // 这里填写上一步创建的AccessKey
    accessKeyId: '上一步创建的',
    accessKeySecret: '上一步创建的',
    // yourRegion填写Bucket所在地域。以华东1(杭州)为例,Region填写为oss-cn-hangzhou。
    region: 'oss-cn-hangzhou',
    authorizationV4: true,
    // yourBucketName填写Bucket名称。
    bucket: '你的Bucket名称',
})

const uploadServer = async (ObjName, fileUrl) => {
    try {
        let result = await client.put(`AAA/${ObjName}`, fileUrl)
        // AAA为文件夹, ObjName为文件名字,可以只写名字,就直接储存在 bucket 的根路径
        // fileUrl就是要传的文件
        return result
    } catch (error) {
        console.log(error)
    }
}

module.exports = { uploadServer }

最后

这样整个流程就完成了,感觉还是有很多不懂的地方,还要多多学习。

这里贴一下阿里云官方关于Node.js上传文件的文档:Node.js文件上传

相关推荐
陈随易3 小时前
在 VSCode 里,把项目一键部署到服务器
前端·后端·程序员
Highcharts.js4 小时前
教程:基于 React + Highcharts 构建一个单页应用程序、按需数据拉取与图表渲染
开发语言·前端·数据结构·react.js·前端框架·highcharts·页面应用
To_OC4 小时前
我被 useState 坑了两次之后,终于把它的脾气摸透了
前端·javascript·react.js
鱼樱前端4 小时前
我用 Claude Code 后,编码效率翻 3 倍。但更值钱的是别的。
前端·后端·ai编程
_lucas5 小时前
给知识库网站接入AI问答
前端·ai编程·全栈
前端糕手5 小时前
前端面试题大全:JavaScript + Vue3 + React + TypeScript + 工程化 + 性能优化
前端
我不叫武6 小时前
一个用 Rust 写的离线编码查询桌面工具
前端
Web4Browser7 小时前
指纹浏览器 API 自动化怎么接:启动 Profile、获取 CDP 端点并连接自动化框架
前端·网络·typescript·自动化
Patrick_Wilson7 小时前
从 React 到 Flutter:写给前端的一张跨端知识地图
前端·flutter·react.js
颜酱7 小时前
06 | 把 meta_config 同步进 MySQL(生成阶段)
前端·人工智能·后端