Skip to content

nodejs 签名前端直传京东云 OSS

nodejs

ts
import AWS from 'npm:aws-sdk';
import { fail, success } from "../utils/resJson.ts";
import dayjs from "dayjs";
import { makeRandomString2 } from "../utils/fn.ts";

export const JD_OSS_AccessKeyId = Deno.env.get("JD_OSS_AccessKeyId")
export const JD_OSS_SecretAccessKey = Deno.env.get("JD_OSS_SecretAccessKey")

const bucketName = '桶名称';

const s3: any = new AWS.S3({ apiVersion: '2006-03-01' });
s3.endpoint = "https://s3.cn-south-1.jdcloud-oss.com";
s3.config.update({
  accessKeyId: JD_OSS_AccessKeyId,
  secretAccessKey: JD_OSS_SecretAccessKey,
  signatureVersion: "v4"
})

const app = new Hono().basePath('/api/oss/jd')

// 上传文件 预签名url
app.post('/upload/preUrl', async (c) => {
  const { filename } = await c.req.json();
  if (!filename) {
    fail('文件名称必传')
  }

  const res = await generatePresignedUrl(filename)
  return c.json(success('', res));

});

// 生成预签名 URL
export const generatePresignedUrl = async (filename: string) => {
  // 服务端生成文件名
  const objectKey = `baby/uploads/${dayjs().format('YYYYMMDD')}/${dayjs().format('HHmmss')}_${makeRandomString2(6)}_${filename}`

  const params = {
    Bucket: bucketName,
    Key: objectKey,
    Expires: 60, // URL有效期,单位秒,例如60秒后过期
    ContentType: 'application/octet-stream', // 支持任意文件类型  application/octet-stream
    // ContentType: 'image/png', // 支持任意文件类型  image/png
  };

  const uploadUrl = await s3.getSignedUrlPromise('putObject', params);
  console.log(uploadUrl, 'uploadUrl');
  return { objectKey, uploadUrl };
};

/**
 * 获取临时文件访问地址
 * @param objectKey 文件储存路径
 */
export async function getTempUrl(objectKey: string) {
  // const objectKey = 'baby/首页.png'; // 如 'folder/filename.jpg'
  const params = {
    Bucket: bucketName,
    Key: objectKey,
    Expires: 60 // URL有效期,单位秒
  };

  const res: any = await new Promise((resolve, reject) => {
    s3.getSignedUrl('getObject', params, (err: any, url: string) => {
      if (err) {
        resolve(fail(err.message, err));
      } else {
        resolve(success('', { url }));
      }
    });
  })

  return res;
}

/**
 * 获取文件列表
 */
export async function getObjectList() {
  const res: any = await new Promise((resolve, reject) => {
    // 列出存储桶中的所有对象
    s3.listObjectsV2({ Bucket: bucketName }, (err: any, data: any) => {
      if (err) {
        console.log(err, err.stack); // 打印错误信息
        resolve(fail(err.message, err));
      } else {
        console.log(data); // 打印对象列表,包括文件和文件夹(如果有权限)
        // data.Contents.forEach((item: any) => {
        //   console.log(item.Key); // 打印每个对象的键(即文件名或路径)
        // });
        resolve(success('', data));
      }
    })


  })

  return res;
}

vue3

vue
<template>
  <div class="page-box">
    <input type="file" @change="handleFileUpload" />
  </div>
</template>

<script setup>
import { http } from '@/utils/request';

const handleFileUpload = async (event) => {
  const file = event.target.files[0];
  try {
    // 获取预签名 URL
    const { data: { objectKey, uploadUrl } } = await http.post('/api/oss/jd/upload/preUrl', { filename: file.name });
    console.log(objectKey, 'objectKey');

    // 直传文件到京东云 OSS
    const response = await fetch(uploadUrl, {
      method: 'PUT',
      body: file,
      headers: { 'Content-Type': file.type },
    });

    if (response.ok) {
      console.log('上传成功');
    }
  } catch (error) {
    console.error('上传失败:', error);
  }
};
</script>