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

开头

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

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

前端

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

 <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方法,他接收一个参数对象如下:

{
    "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方法把文件添加进去,随后调用接口将文件传到后端。

    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,不然后端是收不到文件格式的文件的。

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

完整代码

// 组件.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 中

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

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

{
  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保存到数据库以及返回到前端。

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,剩下的看注释就好了。

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文件上传

  • 29
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值