使用 NextJS + Fetch + Api 路由 + Typescript 上传文件
您将学习如何使用 React、NextJs 和 Fetch API 上传文件。 首先,让我们通过运行来创建 NextJs 应用程序: yarn create next-app --typescript 进入全屏模式 退出全屏模式 安装完成后,在http://localhost:3000上运行 yarn dev 启动开发服务器。 如果您打开该页面,您将看到类似于以下内容的内容: [](https:/
您将学习如何使用 React、NextJs 和 Fetch API 上传文件。
首先,让我们通过运行来创建 NextJs 应用程序:
yarn create next-app --typescript
进入全屏模式 退出全屏模式
安装完成后,在http://localhost:3000上运行 yarn dev 启动开发服务器。
如果您打开该页面,您将看到类似于以下内容的内容:
[](https://res.cloudinary.com/practicaldev/image/fetch/s--cW0rxLL6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to -uploads.s3.amazonaws.com/uploads/articles/nd0yuu2h17ytdnpb6790.png)
现在让我们安装这些包,这将帮助我们解析表单数据:
yarn add -D formidable @types/formidable
进入全屏模式 退出全屏模式
创建表格
我们将创建小表单,我们可以在其中上传文件。我将简化代码以使其更清晰。
转到pages/index.js
并将所有默认代码替换为以下内容:
import type { NextPage } from 'next'
import React from "react";
const Home: NextPage = () => {
const [isLoading, setIsLoading] = React.useState(false);
const inputFileRef = React.useRef<HTMLInputElement | null>(null);
const handleOnClick = async (e: React.MouseEvent<HTMLInputElement>) => {
/* Prevent form from submitting by default */
e.preventDefault();
/* If file is not selected, then show alert message */
if (!inputFileRef.current?.files?.length) {
alert('Please, select file you want to upload');
return;
}
setIsLoading(true);
/* Add files to FormData */
const formData = new FormData();
Object.values(inputFileRef.current.files).forEach(file => {
formData.append('file', file);
})
/* Send request to our api route */
const response = await fetch('/api/upload', {
method: 'POST',
body: formData
});
const body = await response.json() as { status: 'ok' | 'fail', message: string };
alert(body.message);
if (body.status === 'ok') {
inputFileRef.current.value = '';
// Do some stuff on successfully upload
} else {
// Do some stuff on error
}
setIsLoading(false);
};
return (
<form>
<div>
<input type="file" name="myfile" ref={inputFileRef} multiple />
</div>
<div>
<input type="submit" value="Upload" disabled={isLoading} onClick={handleOnClick} />
{isLoading && ` Wait, please...`}
</div>
</form>
)
}
export default Home
进入全屏模式 退出全屏模式
这里我们使用多个文件上传。如果您只想上传一个文件,请从input:file
中删除multiple
:
<input type="file" name="myfile" ref={inputFileRef} />
进入全屏模式 退出全屏模式
API路由
让我们创建一个端点,我们将在其中处理上传的文件。
创建filepages/api/upload.ts
:
import type { NextApiRequest, NextApiResponse } from 'next'
import { promises as fs } from "fs";
import path from "path";
import formidable, { File } from 'formidable';
/* Don't miss that! */
export const config = {
api: {
bodyParser: false,
}
};
type ProcessedFiles = Array<[string, File]>;
const handler = async (req: NextApiRequest, res: NextApiResponse) => {
let status = 200,
resultBody = { status: 'ok', message: 'Files were uploaded successfully' };
/* Get files using formidable */
const files = await new Promise<ProcessedFiles | undefined>((resolve, reject) => {
const form = new formidable.IncomingForm();
const files: ProcessedFiles = [];
form.on('file', function (field, file) {
files.push([field, file]);
})
form.on('end', () => resolve(files));
form.on('error', err => reject(err));
form.parse(req, () => {
//
});
}).catch(e => {
console.log(e);
status = 500;
resultBody = {
status: 'fail', message: 'Upload error'
}
});
if (files?.length) {
/* Create directory for uploads */
const targetPath = path.join(process.cwd(), `/uploads/`);
try {
await fs.access(targetPath);
} catch (e) {
await fs.mkdir(targetPath);
}
/* Move uploaded files to directory */
for (const file of files) {
const tempPath = file[1].filepath;
await fs.rename(tempPath, targetPath + file[1].originalFilename);
}
}
res.status(status).json(resultBody);
}
export default handler;
进入全屏模式 退出全屏模式
恭喜,我们完成了!你可以测试你的表格!
所有文件都将保存在项目根目录内的目录/uploads
中。
使用Api路由做代理
在这里,我建议您假设,我们需要将文件传输到其他地方到另一台服务器,因为我们不想存储它们并对文件进行困难的操作。
添加一些新包:
yarn add -D form-data node-fetch
进入全屏模式 退出全屏模式
改变你/pages/api/upload.ts to
:
import type { NextApiRequest, NextApiResponse } from 'next'
import fs from "fs";
import fetch from "node-fetch";
import FormData from 'form-data';
import formidable, { File } from 'formidable';
export const config = {
api: {
bodyParser: false,
}
};
type ProcessedFiles = Array<[string, File]>;
const handler = async (req: NextApiRequest, res: NextApiResponse) => {
let status = 200,
resultBody = { status: 'ok', message: 'Files were uploaded successfully' };
/* Get files using formidable */
const files = await new Promise<ProcessedFiles | undefined>((resolve, reject) => {
const form = new formidable.IncomingForm();
const files: ProcessedFiles = [];
form.on('file', function (field, file) {
files.push([field, file]);
})
form.on('end', () => resolve(files));
form.on('error', err => reject(err));
form.parse(req, () => {
//
});
}).catch(e => {
console.log(e);
status = 500;
resultBody = {
status: 'fail', message: 'Upload error'
}
});
if (files?.length) {
/* Add files to FormData */
const formData = new FormData();
for (const file of files) {
formData.append(file[0], fs.createReadStream(file[1].filepath));
}
/* Send request to another server */
const response = await fetch('PATH_TO_ANOTHER_SERVER', {
headers: formData.getHeaders(),
method: 'POST',
body: formData
});
// Do anything you need with response
}
res.status(status).json(resultBody);
}
export default handler;
进入全屏模式 退出全屏模式
不要忘记替换PATH_TO_ANOTHER_SERVER
。
就是这样,享受!完整回购https://github.com/gapon2401/upload-files-nextjs
更多推荐
所有评论(0)