如何使用 Next JS 和 Zeit Now 和强大的无服务器将文件上传到 S3

Joh*_*Kim 3 upload amazon-s3 formidable next.js serverless

抱歉我英语不好。它适用于本地主机,但不适用于生产。(使用 ZEIT NOW 部署)

这是上传.ts

import { NextApiRequest, NextApiResponse } from 'next'
import AWS from 'aws-sdk';
const formidable = require("formidable-serverless");
AWS.config.region = 'ap-northeast-2';

export const config = {
  api: {
    bodyParser: false,
  }
}

export default async (req:NextApiRequest, res:NextApiResponse) => {
  const data = await new Promise(function(resolve, reject) {
    const form = formidable();

    form.keepExtensions = true;
    form.keepFilename = true;

    form.parse(req, (err:any, fields:any, files:any) => {

      const s3 = new AWS.S3({
        accessKeyId: process.env.AWS_ACCESS_KEY_CODE,
        secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY_CODE
      });

      const params = {
        Bucket: 'mybucket',
        Key: `folder/${files.file.name}`,
        ACL: 'public-read',
        Body: require('fs').createReadStream(files.file.path);
      };

      s3.upload(params, (err:any, data:any) => {
        resolve({ err, data });
      });

      if (err) return reject(err);
      resolve({ fields, files });
    });

  });
}
Run Code Online (Sandbox Code Playgroud)

我想我不能在无服务器中使用“fs”。但我找不到其他上传方式。帮帮我谢谢!

lee*_*rob 8

以下是如何使用 Next.js 将图像上传到 S3 的示例。

// pages/api/upload-url.js

import aws from 'aws-sdk';

export default async function handler(req, res) {
  aws.config.update({
    accessKeyId: process.env.ACCESS_KEY,
    secretAccessKey: process.env.SECRET_KEY,
    region: process.env.REGION,
    signatureVersion: 'v4',
  });

  const s3 = new aws.S3();
  const post = await s3.createPresignedPost({
    Bucket: process.env.BUCKET_NAME,
    Fields: {
      key: req.query.file,
    },
    Expires: 60, // seconds
    Conditions: [
      ['content-length-range', 0, 1048576], // up to 1 MB
    ],
  });

  res.status(200).json(post);
}
Run Code Online (Sandbox Code Playgroud)

这利用了预先签名的 POST,这有助于将计算从您的服务器卸载到 AWS。然后,您可以在前端调用此 URL 来发送文件。

export default function Upload() {
  const uploadPhoto = async (e) => {
    const file = e.target.files[0];
    const filename = encodeURIComponent(file.name);
    const res = await fetch(`/api/upload-url?file=${filename}`);
    const { url, fields } = await res.json();
    const formData = new FormData();

    Object.entries({ ...fields, file }).forEach(([key, value]) => {
      formData.append(key, value);
    });

    const upload = await fetch(url, {
      method: 'POST',
      body: formData,
    });

    if (upload.ok) {
      console.log('Uploaded successfully!');
    } else {
      console.error('Upload failed.');
    }
  };

  return (
    <>
      <p>Upload a .png or .jpg image (max 1MB).</p>
      <input
        onChange={uploadPhoto}
        type="file"
        accept="image/png, image/jpeg"
      />
    </>
  );
}
Run Code Online (Sandbox Code Playgroud)

https://github.com/leerob/nextjs-aws-s3


Kay*_*Kay 8

这是我使用 nextjs、multer (typescript) 的上传示例

.env.local

AWS_ACCESS_KEY_ID=<your-key-id>
AWS_SECRET_ACCESS_KEY=<your-access-key>

BUCKET_NAME=<your-bucket-name>
Run Code Online (Sandbox Code Playgroud)

@utils/runMiddleware ( https://nextjs.org/docs/api-routes/api-middlewares )

AWS_ACCESS_KEY_ID=<your-key-id>
AWS_SECRET_ACCESS_KEY=<your-access-key>

BUCKET_NAME=<your-bucket-name>
Run Code Online (Sandbox Code Playgroud)

@utils/aws/upload.ts

import { NextApiRequest, NextApiResponse } from 'next';

const runMiddleware = (req: NextApiRequest, res: NextApiResponse, fn: any) => {
  return new Promise((resolve, reject) => {
    fn(req, res, (result: unknown) => {
      if (result instanceof Error) {
        return reject(result);
      }

      return resolve(result);
    });
  });
};

export default runMiddleware;
Run Code Online (Sandbox Code Playgroud)

/api/upload.ts

import { config, S3 } from 'aws-sdk';

// Set the region (other credentials are in process.env)
config.update({ region: 'ap-northeast-2' });

// Create S3 service object
const s3 = new S3({ apiVersion: '2006-03-01' });

const upload = async (bucket: string, fileName: string, body: Buffer) => {
  return new Promise((resolve, reject) => {
    s3.upload(
      {
        Bucket: bucket,
        Key: fileName,
        Body: body,
        ACL: 'public-read',
      },
      (err, data) => {
        if (err) reject(err);
        else resolve(data);
      },
    );
  });
};

export default upload;
Run Code Online (Sandbox Code Playgroud)