node.js 实战——express图片保存到本地或服务器(七牛云、腾讯云、阿里云)

本地

✅ 使用formidable 读取表单内容

bash 复制代码
npm i formidable 

✅ 使用mime-types 获取图片后缀

bash 复制代码
npm install mime-types

✅ js 中提交form表单

javascript 复制代码
 document.getElementById('uploadForm').addEventListener('submit', function(e){

        e.preventDefault();
        const blob =preview._blob;
        if(!blob){
            alert("请先选择并裁剪头像");
            return;
        }
        const formData = new FormData();
        formData.append('file', blob);

        //未裁剪使用代码
        // const file =input.files[0];
        // if(!file) return alert('Please upload a valid image!');
        //
        // let formData = new FormData();
        // formData.append('file', file);

        let xhr = new XMLHttpRequest();
        xhr.open('POST', '/users/upload-avatar');

        xhr.upload.addEventListener('progress', (e) => {
            if(e.lengthComputable){
                let percent = Math.round((e.loaded / e.total) * 100);
                progressWrapper.classList.remove('d-none');
                progressBar.style.width= percent + '%';
                progressBar.innerText = percent + '%';
            }
        })


        xhr.onload =function () {
            if(xhr.status === 200) {
                alert("successfully uploaded!");
            }else{
                alert("fail to upload");
            }
        }
        xhr.send(formData);

    })

✅ express 中routers的js

javascript 复制代码
var express = require('express');
var router = express.Router();
const { IncomingForm } = require('formidable'); // ✅ 注意不是直接 require('formidable')
const path = require('path');
const mime = require('mime-types')


/* GET users listing. */
router.get('/', function(req, res, next) {

  res.render('user', { title: '订餐系统' });
});

router.post('/upload-avatar', function(req, res, next) {
  //创建表单对象
  const form =new IncomingForm({
    multiple:true,
    //设置上传文件的保存目录
    uploadDir:__dirname+'/../public/uploads/',
    //保存文件后缀
    keepExtension:true,
    // 支持多文件
    multiples:true,
    filename:(name,ext,part,form)=>{
      const timestamp = Date.now();
      let extension = mime.extension(part.mimetype) || '';
      return `${timestamp}-${Math.random().toString(36).slice(2)}${extension ? '.' + extension : ''}`;
    }
  });
  //
  form.parse(req,function(err,fields,files){
    if(err){
      next(err);
      return;
    }



    res.json({files,files});

  })

})

module.exports = router;



七牛云

✅ 实现步骤概览

  1. 使用 formidable 获取上传的图片流或临时文件路径
  2. 使用 qiniu SDK 上传到七牛云对象存储
  3. 返回文件 URL 给前端

✅ 安装依赖

bash 复制代码
npm install formidable qiniu

✅ 七牛云配置准备

你需要准备这些信息:

• accessKey

• secretKey

• bucket(空间名称)

• domain(空间绑定的 CDN 域名)

✅ 完整 Express + formidable + 七牛 上传示例

javascript 复制代码
const express = require('express');
const { IncomingForm } = require('formidable');
const fs = require('fs');
const path = require('path');
const qiniu = require('qiniu');

const app = express();

// 七牛配置
const accessKey = '你的AccessKey';
const secretKey = '你的SecretKey';
const bucket = '你的Bucket';
const domain = 'http://你的空间域名'; // 绑定的 CDN 域名(带 http)

// 上传凭证
const mac = new qiniu.auth.digest.Mac(accessKey, secretKey);
const putPolicy = new qiniu.rs.PutPolicy({ scope: bucket });
const uploadToken = putPolicy.uploadToken(mac);

// 七牛配置对象
const config = new qiniu.conf.Config();
// 根据你空间的 Zone 设置,如华东为 Zone_z0
config.zone = qiniu.zone.Zone_z0;

// 表单上传接口
app.post('/upload', (req, res) => {
  const form = new IncomingForm({ multiples: false, keepExtensions: true });

  form.parse(req, (err, fields, files) => {
    if (err) return res.status(500).json({ error: '上传失败' });

    const file = files.images || files.file;
    const localFilePath = file.filepath || file.path; // 不同版本字段不同
    const fileExt = path.extname(file.originalFilename || file.name || '');
    const fileName = `${Date.now()}-${Math.random().toString(36).slice(2)}${fileExt}`;

    const putExtra = new qiniu.form_up.PutExtra();
    const formUploader = new qiniu.form_up.FormUploader(config);

    formUploader.putFile(uploadToken, fileName, localFilePath, putExtra, (respErr, respBody, respInfo) => {
      // 删除本地临时文件(可选)
      fs.unlink(localFilePath, () => {});

      if (respErr) return res.status(500).json({ error: '七牛上传失败' });

      if (respInfo.statusCode === 200) {
        res.json({
          success: true,
          url: `${domain}/${respBody.key}` // 返回七牛图片地址
        });
      } else {
        res.status(respInfo.statusCode).json({ error: respBody });
      }
    });
  });
});

app.listen(3000, () => {
  console.log('Server running on http://localhost:3000');
});

✅ 七牛空间设置建议

设置项 建议
空间类型 公有(或使用私有 + 临时下载链接)
绑定 CDN 域名 用于外链图片地址
设置防盗链 生产环境建议设置 Referer 防盗链

✅ 最终效果

上传成功后,前端将得到形如:

{

"success": true,

"url": "http://cdn.yourdomain.com/1700000000-abc123.jpg"

}

前端就可以将这个 URL 显示为图片头像或多图预览。

腾讯云

如果你要把上传的图片保存到 腾讯云对象存储(COS),可以使用官方的 COS Node.js SDK。

✅ 安装依赖

javascript 复制代码
npm install formidable cos-nodejs-sdk-v5

✅ 腾讯云 COS 准备

你需要准备以下内容:

参数来源 (腾讯云后台)
SecretId 访问管理 - API 密钥管理
SecretKey 同上
Bucket 例如:example-1250000000
Region 如 ap-nanjing

✅ 后端上传图片到腾讯云 COS

javascript 复制代码
const express = require('express');
const { IncomingForm } = require('formidable');
const COS = require('cos-nodejs-sdk-v5');
const fs = require('fs');
const path = require('path');

const app = express();

// 腾讯云配置
const cos = new COS({
  SecretId: '你的SecretId',
  SecretKey: '你的SecretKey',
});

// 上传接口
app.post('/upload', (req, res) => {
  const form = new IncomingForm({ keepExtensions: true });

  form.parse(req, (err, fields, files) => {
    if (err) return res.status(500).json({ error: '上传失败' });

    const file = files.file || files.image || files.images;
    const filePath = file.filepath || file.path;
    const fileExt = path.extname(file.originalFilename || file.name || '');
    const fileName = `uploads/${Date.now()}-${Math.random().toString(36).slice(2)}${fileExt}`;

    // 上传到 COS
    cos.putObject({
      Bucket: '你的Bucket-数字ID',
      Region: 'ap-你的地域',
      Key: fileName,
      Body: fs.createReadStream(filePath),
      ContentLength: fs.statSync(filePath).size,
    }, (err, data) => {
      // 删除临时文件
      fs.unlink(filePath, () => {});

      if (err) return res.status(500).json({ error: 'COS上传失败', detail: err });

      const url = `https://${data.Location}`;
      res.json({ success: true, url });
    });
  });
});

app.listen(3000, () => {
  console.log('Server started on http://localhost:3000');
});

✅ 示例返回

javascript 复制代码
{
  "success": true,
  "url": "https://example-1250000000.cos.ap-nanjing.myqcloud.com/uploads/1700000000-abc123.jpg"
}

🛡️ 注意事项

  • Bucket 名称必须是:- 格式,例如:mybucket-1250000000
  • 记得绑定好 CNAME 或设置跨域(CORS)策略以支持前端访问
  • 腾讯云对象存储会自动生成公网访问链接(基于默认域名)

阿里云

如果你想将上传的图片保存到 阿里云 OSS(对象存储服务),可以使用官方的 ali-oss Node.js SDK。

✅ 安装依赖

javascript 复制代码
npm install formidable ali-oss

✅ 准备阿里云 OSS 配置

你需要这些信息:

项目 获取方式
accessKeyId 阿里云账号控制台 → RAM 用户 → 访问密钥管理
accessKeySecret 同上
bucket OSS 控制台创建的 Bucket 名称
region Bucket 所在地域,如 oss-cn-hangzhou
cdnDomain 推荐绑定自定义 CDN 域名,如 https://img.example.com

✅ 后端 Express 示例

javascript 复制代码
const express = require('express');
const { IncomingForm } = require('formidable');
const OSS = require('ali-oss');
const fs = require('fs');
const path = require('path');

const app = express();

// 阿里云 OSS 配置
const client = new OSS({
  region: 'oss-cn-hangzhou',          // 修改为你的地域
  accessKeyId: '你的AccessKeyId',
  accessKeySecret: '你的AccessKeySecret',
  bucket: '你的Bucket名称',
});

const cdnDomain = 'https://your-cdn.example.com'; // 可选:绑定的自定义域名

app.post('/upload', (req, res) => {
  const form = new IncomingForm({ keepExtensions: true });

  form.parse(req, async (err, fields, files) => {
    if (err) return res.status(500).json({ error: '上传失败' });

    const file = files.file || files.image || files.images;
    const filePath = file.filepath || file.path;
    const ext = path.extname(file.originalFilename || file.name || '');
    const fileName = `uploads/${Date.now()}-${Math.random().toString(36).slice(2)}${ext}`;

    try {
      const result = await client.put(fileName, filePath);
      fs.unlink(filePath, () => {}); // 删除临时文件

      res.json({
        success: true,
        url: cdnDomain ? `${cdnDomain}/${fileName}` : result.url,
      });
    } catch (ossErr) {
      res.status(500).json({ error: 'OSS上传失败', detail: ossErr });
    }
  });
});

app.listen(3000, () => {
  console.log('Server running at http://localhost:3000');
});

✅ 示例上传成功响应

javascript 复制代码
{
  "success": true,
  "url": "https://your-cdn.example.com/uploads/1700000000-abc123.jpg"
}

📝 注意事项

  • 推荐在 OSS 控制台开启跨域(CORS) 支持,方便前端访问
  • 上传后图片即刻可通过公网域名访问
  • 如果你使用的是绑定 CDN 的域名,请确保缓存配置正确(或开启自动刷新)
相关推荐
Q_Q19632884752 小时前
python小说网站管理系统-小说阅读系统
开发语言·spring boot·python·django·flask·node.js·php
m0_zj5 小时前
57.[前端开发-前端工程化]Day04-webpack插件模式-搭建本地服务器
前端·webpack·node.js
盛夏绽放5 小时前
Vue3 + Node.js 实现客服实时聊天系统(WebSocket + Socket.IO 详解)
websocket·网络协议·node.js
m0_zj9 小时前
58.[前端开发-前端工程化]Day05-webpack-Git安装-配置-Git命令
前端·webpack·node.js
Attacking-Coder9 小时前
前端面试宝典---JavaScript import 与 Node.js require 的区别
前端·javascript·node.js
大宁宁吖10 小时前
使用node.js创建一个简单的服务器
node.js
梦想平凡11 小时前
开元类双端互动组件部署实战全流程教程(第1部分:环境与搭建)
运维·服务器·前端·游戏·node.js
哎哟喂_!11 小时前
Node.js vs 浏览器中的JavaScript:区别全解析
开发语言·javascript·node.js
OpenTiny社区11 小时前
Node.js 技术原理分析系列9——Node.js addon一文通
node.js