还不会文件上传?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文件上传

相关推荐
冰镇屎壳郎8 分钟前
前端安全 常见的攻击类型及防御措施
前端·安全·前端安全
2401_8576176214 分钟前
“无缝购物体验”:跨平台网上购物商城的设计与实现
java·开发语言·前端·安全·架构·php
2401_8574396923 分钟前
智慧社区电商系统:提升用户体验的界面设计
前端·javascript·php·ux
我是高手高手高高手32 分钟前
ThinkPHP8多应用配置及不同域名访问不同应用的配置
linux·服务器·前端·php
小李小李不讲道理35 分钟前
行动+思考 | 2024年度总结
前端·程序员·年终总结
csdnLN1 小时前
$.ajax() 对应事件done() 、fail()、always() 的用法
前端·javascript·ajax
甜味橘阳1 小时前
echarts地图可视化展示
前端·javascript·echarts
bloxed2 小时前
前端文件下载多方式集合
前端·filedownload
余生H2 小时前
前端Python应用指南(三)Django vs Flask:哪种框架适合构建你的下一个Web应用?
前端·python·django
LUwantAC2 小时前
CSS(四)display和float
前端·css