Upload File: multipart/form-data Usage
multipart/form-data
v.s. application/x-www-form-urlencoded
multipart/form-data
和 application/x-www-form-urlencoded
是两种常用的 HTTP 表单数据编码方式,它们在 Web 应用程序中用于提交表单数据到服务器。尽管它们的目的相似,但它们在实现和使用上有一些关键的差异。
相同点
- 表单数据传输:它们都用于通过 HTTP POST 请求传输表单数据到服务器。
- 浏览器支持:现代 Web 浏览器都支持这两种编码类型,并能够自动处理表单数据的编码和解码。
- 数据类型:它们可以传输文本字段,如文本输入、选择框、复选框等。
差异点
-
二进制数据支持:
multipart/form-data
:支持文件和二进制数据的传输。它使用特殊的分隔符来分隔各个表单字段,并且每个字段都有自己的内容类型(MIME type)。application/x-www-form-urlencoded
:不支持文件和二进制数据的传输。所有数据都被编码为键值对,并且对于非 ASCII 字符使用百分比编码(URL 编码)。
-
数据结构:
multipart/form-data
:数据以多部分(multipart)的形式发送,每个部分可以包含不同类型的数据,如文本和文件。application/x-www-form-urlencoded
:数据以 单一的 URL 编码字符串的形式发送,所有的数据都编码在 URL 的查询参数中。
-
请求体大小:
multipart/form-data
:由于支持文件和二进制数据,请求体的大小通常较大。application/x-www-form-urlencoded
:请求体通常较小,因为它只包含文本数据。
-
请求头:
multipart/form-data
:请求头中包含Content-Type
,其值后面跟着一个边界字符串(boundary),用于分隔消息体中的各个部分。application/x-www-form-urlencoded
:请求头中包含Content-Type
,其值为application/x-www-form-urlencoded
。
-
解析复杂性:
multipart/form-data
:服务器端需要解析多部分消息体,这可能涉及到更复杂的逻辑来处理不同类型的数据。application/x-www-form-urlencoded
:服务器端通常更容易解析,因为数据以简单的键值对形式存在。
-
用途:
multipart/form-data
:通常用于文件上传和提交包含文件、图片等二进制数据的表单。application/x-www-form-urlencoded
:通常用于提交文本数据的表单,如登录表单、搜索表单等。
总结来说,multipart/form-data
编码类型适合于文件上传和传输二进制数据的场景,而 application/x-www-form-urlencoded
则适用于传输文本数据的表单。开发者应根据实际需求选择合适的编码类型来处理表单数据。
React + FastAPI
multipart/form-data
是一种编码类型,它在 Web 开发中有着广泛的应用场景,尤其是在需要上传文件的情况下。结合 React 和 FastAPI,我们可以创建一个端到端的文件上传解决方案。以下是 multipart/form-data
在这种场景下的使用说明:
React 端
-
创建表单:在 React 应用中,创建一个表单,允许用户选择文件进行上传。你需要设置表单的
enctype
属性为multipart/form-data
,以便正确编码表单数据。<form onSubmit={handleUpload}>
<input type="file" name="file" accept="image/*" />
<button type="submit">Upload</button>
</form> -
处理表单提交:使用 React Hook Form 或其他表单库来处理表单提交事件。在提交事件中,你可以使用 Axios 或其他 HTTP 客户端库来发送请求。
const handleUpload = async event => {
event.preventDefault();
const formData = new FormData(event.target);
// 发送请求...
}; -
发送请求:使用 Axios 的
post
方法,并传递FormData
对象作为请求体,以便发送文件数据。const handleUpload = async event => {
event.preventDefault();
const formData = new FormData(event.target);
try {
const response = await axios.post('/upload', formData, {
headers: {
'Content-Type': 'multipart/form-data',
},
});
console.log(response.data);
} catch (error) {
console.error(error);
}
};
FastAPI 端
-
定义路由:在 FastAPI 应用中,定义一个路由来处理文件上传请求。使用
File
和UploadFile
类型来声明文件参数。from fastapi import FastAPI, File, UploadFile
app = FastAPI()
@app.post("/upload")
async def upload_file(file: UploadFile = File(...)):
# 处理文件...
return {"filename": file.filename} -
安装依赖:为了处理
multipart/form-data
,FastAPI 需要python-multipart
库。安装它以支持流式解析。pip install python-multipart
-
处理文件:在 FastAPI 路由函数中,你可以读取上传的文件,将其保存到服务器或进行进一步处理。
@app.post("/upload")
async def upload_file(file: UploadFile = File(...)):
file_path = f"./uploads/{file.filename}"
with open(file_path, "wb") as buffer:
buffer.write(await file.read())
return {"filename": file.filename} -
多文件上传:FastAPI 同样支持多文件上传。只需将文件参数声明为
List[UploadFile]
类型即可。@app.post("/uploadfiles")
async def upload_files(files: List[UploadFile] = File(...)):
# 处理多个文件...
return {"filenames": [file.filename for file in files]}
通过结合 React 和 FastAPI,你可以创建一个功能完善的文件上传系统,它能够在前端通过用户友好的界面选择和上传文件,并在后端安全、高效地处理这些文件。使用 multipart/form-data
编码确保了文件数据的正确传输,同时也支持其他表单数据的发送。
antd or arco + FastAPI
在 React 应用中,antd
的 Upload
组件提供了一个简单且强大的界面来处理文件上传。结合 multipart/form-data
和 FastAPI 后端,你可以创建一个高效的文件上传功能。以下是如何使用 antd Upload
组件与 FastAPI 后端结合的步骤:
React 端使用 antd Upload
组件
-
创建上传组件:在你的 React 组件中,使用
antd
的Upload
组件来创建一个上传界面。Upload
组件提供了多种配置选项,包括自定义请求头、上传方法和上传地址等。import { Upload, Button, message } from 'antd';
import { UploadOutlined } from '@ant-design/icons';
const props = {
action: '/upload', // 你的 FastAPI 后端上传接口地址
onChange(info) {
if (info.file.status !== 'uploading') {
console.log(info.file, info.fileList);
}
if (info.file.status === 'done') {
message.success(`${info.file.name} file uploaded successfully`);
} else if (info.file.status === 'error') {
message.error(`${info.file.name} file upload failed.`);
}
},
// 可以添加其他属性,如 headers, data 等
};
const MyUploadComponent = () => (
<Upload {...props}>
<Button icon={<UploadOutlined />}>Click to Upload</Button>
</Upload>
);
export default MyUploadComponent; -
自定义上传方法(可选):如果你需要自定义上传方法,可以通过设置
customRequest
属性来实现。例如,你可以使用 Axios 来发送自定义的 HTTP 请求。const customRequest = async ({ file, onSuccess, onError }) => {
const formData = new FormData();
formData.append('file', file);
try {
const response = await axios.post('/upload', formData, {
headers: {
'Content-Type': 'multipart/form-data',
},
});
onSuccess(response.data);
} catch (error) {
onError(error);
}
};
const props = {
// ...其他属性
customRequest,
};
React 端使用 arco-upload
组件
-
创建上传组件:在你的 React 组件中,使用
arco-upload
组件来创建一个上传界面。arco-upload
组件提供了多种配置选项,包括自定义请求头、上传方法和上传地址等。import React from 'react';
import { Upload, Button } from 'arco-design';
const MyUploadComponent = () => {
const props = {
action: '/upload', // 你的 FastAPI 后端上传接口地址
onChange: info => {
if (info.file.status !== 'uploading') {
console.log(info.file, info.fileList);
}
if (info.file.status === 'done') {
// 可以在这里显示上传成功的提示信息
console.log(`File uploaded successfully: ${info.file.name}`);
} else if (info.file.status === 'error') {
// 可以在这里显示上传失败的提示信息
console.error(`File upload failed: ${info.file.name}`);
}
},
// 可以添加其他属性,如 headers, data 等
};
return (
<Upload {...props}>
<Button type="primary">Click to Upload</Button>
</Upload>
);
};
export default MyUploadComponent; -
自定义上传方法(可选):如果你需要自定义上传方法,可以通过设置
customRequest
属性来实现。例如,你可以使用 Axios 来发送自定义的 HTTP 请求。const customRequest = options => {
return new Promise((resolve, reject) => {
const { file, onProgress, onSuccess, onError } = options;
const formData = new FormData();
formData.append('file', file);
Axios.post('/upload', formData, {
headers: {
'Content-Type': 'multipart/form-data',
},
onUploadProgress: event => {
onProgress({ percent: (event.loaded / event.total) * 100 });
},
})
.then(response => {
onSuccess(response.data);
})
.catch(error => {
onError(error);
});
});
};
const props = {
// ...其他属性
customRequest,
};
FastAPI 端处理上传
-
创建 FastAPI 应用:创建一个新的 FastAPI 应用,并定义一个上传接口。使用
File
和UploadFile
类型来接收上传的文件。from fastapi import FastAPI, File, UploadFile
app = FastAPI()
@app.post("/upload")
async def upload_file(file: UploadFile = File(...)):
# 保存文件到服务器或其他处理
filename = file.filename
with open(f"./{filename}", "wb") as buffer:
buffer.write(await file.read())
return {"message": f"File {filename} uploaded successfully."} -
运行 FastAPI 应用:使用
uvicorn
或其他 ASGI 服务器来运行你的 FastAPI 应用。uvicorn your_fastapi_app:app --reload
通过上述步骤,你可以在 React 应用中使用 antd Upload
组件来提供一个用户友好的文件上传界面,同时在后端使用 FastAPI 来处理上传的文件。这种结合方式不仅提高了用户体验,也使得文件上传过程更加稳定和可靠。