文件上传
Netty-Boot 文件上传处理
在 Netty-Boot
项目中,文件上传是一个常见的需求。Netty 提供了强大的 HTTP 处理能力,可以通过 multipart/form-data
实现文件上传。本文将介绍如何通过 Netty-Boot
处理文件上传,并解析其工作原理。
文件上传原理
- HTTP POST 和
multipart/form-data
:文件上传通常通过 HTTP POST 请求,Content-Type
设置为multipart/form-data
。这使得文件和表单数据一起发送到服务器。 - Netty 的
HttpPostRequestDecoder
:Netty 提供了HttpPostRequestDecoder
,它可以解析multipart/form-data
请求,将其中的文件和表单字段分离开来,方便处理。 - 保存文件:在接收到文件数据后,可以将其保存到本地磁盘或进行进一步的处理。Netty 通过
FileUpload
类来表示文件上传项。 - 请求大小限制:默认情况下,Netty 支持的文件大小为 10 MB。如果需要上传更大的文件,可以通过
http.multipart.max-request-size
参数调整大小限制,单位为字节。
文件上传实现
1. 文件上传大小限制配置
默认情况下,Netty 支持的文件上传大小为 10MB。如果需要上传更大的文件,可以在配置文件中增加以下参数:
http.multipart.max-request-size=10485760 # 10MB
如果你需要增加上传文件的大小限制,可以调整此值。例如,20MB:
http.multipart.max-request-size=20971520 # 20MB
2. 创建 UploadHandler
处理上传
在 UploadHandler
类中,我们使用 HttpPostRequestDecoder
解析上传的 multipart/form-data
请求。解析后,可以通过 FileUpload
对象获取上传的文件并将其保存到本地。
package com.litongjava.netty.im.handler;
import java.io.File;
import java.io.IOException;
import com.litongjava.model.body.RespBodyVo;
import com.litongjava.netty.boot.utils.HttpResponseUtils;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.handler.codec.http.HttpHeaderNames;
import io.netty.handler.codec.http.HttpHeaderValues;
import io.netty.handler.codec.http.multipart.DefaultHttpDataFactory;
import io.netty.handler.codec.http.multipart.FileUpload;
import io.netty.handler.codec.http.multipart.HttpPostRequestDecoder;
import io.netty.handler.codec.http.multipart.InterfaceHttpData;
import io.netty.util.CharsetUtil;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class UploadHandler {
public FullHttpResponse upload(ChannelHandlerContext ctx, FullHttpRequest httpRequest) {
// 检查请求是否为 multipart/form-data
if (!httpRequest.method().name().equals("POST")) {
log.error("上传请求不是POST请求");
return createErrorResponse("Invalid request method");
}
String contentType = httpRequest.headers().get(HttpHeaderNames.CONTENT_TYPE);
if (contentType == null || !contentType.startsWith(HttpHeaderValues.MULTIPART_FORM_DATA.toString())) {
log.error("Content-Type 不是 multipart/form-data");
return createErrorResponse("Invalid Content-Type");
}
// 使用 HttpPostRequestDecoder 来解析上传文件
HttpPostRequestDecoder decoder = new HttpPostRequestDecoder(new DefaultHttpDataFactory(false), httpRequest, CharsetUtil.UTF_8);
try {
// 处理每个文件或者表单项
while (decoder.hasNext()) {
InterfaceHttpData data = decoder.next();
if (data != null && data.getHttpDataType() == InterfaceHttpData.HttpDataType.FileUpload) {
FileUpload fileUpload = (FileUpload) data;
if (fileUpload.isCompleted()) {
// 保存文件到本地或处理
File uploadFolder = new File("files");
if (!uploadFolder.exists()) {
uploadFolder.mkdirs();
}
File file = new File("files/" + fileUpload.getFilename());
fileUpload.renameTo(file);
log.info("文件上传成功: {}", file.getAbsolutePath());
}
}
}
} catch (HttpPostRequestDecoder.EndOfDataDecoderException e) {
log.info("所有数据已经处理完毕");
} catch (IOException e) {
log.error("文件上传失败", e);
return createErrorResponse("File upload failed");
} finally {
decoder.destroy(); // 释放资源
}
// 返回成功响应
return createSuccessResponse();
}
private FullHttpResponse createErrorResponse(String message) {
RespBodyVo ok = RespBodyVo.fail(message);
return HttpResponseUtils.json(ok);
}
private FullHttpResponse createSuccessResponse() {
RespBodyVo ok = RespBodyVo.ok();
return HttpResponseUtils.json(ok);
}
}
3. 注册 UploadHandler
处理器
将 UploadHandler
处理器注册到 Netty-Boot
的路由器中,以便接收文件上传请求:
UploadHandler uploadHandler = Aop.get(UploadHandler.class);
httpRequestRouter.add("/upload", uploadHandler::upload);
4. 测试文件上传
通过 curl
或其他 HTTP 客户端工具(如 Postman)测试文件上传:
curl --location --request POST 'http://127.0.0.1/upload' \
--header 'User-Agent: Apifox/1.0.0 (https://apifox.com)' \
--header 'Accept: */*' \
--header 'Host: 127.0.0.1' \
--header 'Connection: keep-alive' \
--header 'Content-Type: multipart/form-data; boundary=--------------------------366765811236362307119867' \
--form 'file=@"textbook-Thomas H. Cormen, Charles E. Leiserson, Ronald L. Rivest, Clifford Stein - Introduction to Algorithms-MIT Press (2022) (2).pdf"'
此命令将文件上传到 http://127.0.0.1/upload
接口。
5. 处理上传请求流程
- POST 请求验证:首先验证上传的请求方法是否为
POST
,并检查Content-Type
是否为multipart/form-data
,如果不是,返回错误响应。 - 文件解析:通过
HttpPostRequestDecoder
解析上传的表单数据,找到文件上传项(FileUpload
)。 - 文件保存:将上传的文件保存到指定目录(
files/
)。如果该目录不存在,则创建目录。 - 返回响应:文件上传成功后,返回一个成功的 JSON 响应。如果上传失败或请求不符合要求,返回错误响应。
总结
本文详细介绍了如何通过 Netty-Boot
实现文件上传。通过配置文件限制上传文件大小,使用 HttpPostRequestDecoder
解析 multipart/form-data
请求,开发者可以轻松处理文件上传请求,并将文件存储到服务器指定目录。