问题解决了!
从updated documentation,现在可以使用新的JakartaStreamMultiPartRequest解决问题:
从 Struts 版本 2.3.18 开始,MultiPartRequest 的新实现
已添加 - JakartaStreamMultiPartRequest。它可以用来处理
大文件,详见WW-3025,但可以简单设置
<constant name="struts.multipart.parser" value="jakarta-stream" />
在 struts.xml 中开始使用它。
来自链接的 JIRA 主体:
当任何大小限制超出时,立即
FileUploadBase.SizeLimitExceededException 或
抛出 FileUploadBase.FileSizeLimitExceededException 并解析
多部分请求在不提供请求参数的情况下终止
进行进一步处理。
这基本上使任何 Web 应用程序都无法处理
大小限制优雅地超出了案例。
我的建议是请求解析应该始终完成以交付
请求参数。超出大小限制的情况/例外可能是
收集以供以后检索,FileSizeLimitExeededException 应该是
映射到 FileItem 以允许对 FileItem 进行一些验证
应用层。这将允许将上传输入字段标记为
如果上传的文件太大,则会出错。
实际上我为此做了一个补丁(见附件)。有了这个补丁,
commons-fileupload 在大小的情况下总是完成请求解析
超出限制,只有在完成解析后才会抛出
如果检测到一个异常。
还有 Chris Cranford 的评论:
我正在为我正在调用的 Struts2 开发一个新的多部分解析器
JakartaStreamMultiPartRequest。
这个多部分解析器的行为与现有的 Jakarta 相同
多部分解析器,除了它使用 Commons FileUpload Streaming
API,而不是将最大请求大小检查委托给文件
上传API,它是在内部完成的,以避免存在的问题
上传 API 中断循环迭代和参数丢失。
太棒了,谢谢大家:)
旧答案
我猜这是由于
的不同行为
- 单个文件(或多个文件)超过其最大定义大小,然后可以在正常进程结束时使用 INPUT 结果重定向回来,并且
- 违反整个请求的最大大小,这将(可能?)破坏任何其他元素解析,因为它是一种安全机制,而不是像文件大小检查这样的功能;
首先解析文件时 (it should depend on their order in the page),如果文件超出了多部分请求大小的限制,则其他字段(表单字段)将不会被读取,因此不会与 INPUT 结果一起返回。
Struts2 uses the Jakarta implementation 用于 MultiPartRequestWrapper:
struts.multipart.parser - 此属性应设置为扩展 MultiPartRequest 的类。目前,该框架附带 Jakarta FileUpload 实现。
可以在Struts2官网or here找到源代码(google起来比较快);这是发布多部分表单时调用的内容:
public void parse(HttpServletRequest request, String saveDir) throws IOException {
try {
setLocale(request);
processUpload(request, saveDir);
} catch (FileUploadBase.SizeLimitExceededException e) {
if (LOG.isWarnEnabled()) {
LOG.warn("Request exceeded size limit!", e);
}
String errorMessage = buildErrorMessage(e, new Object[]{e.getPermittedSize(), e.getActualSize()});
if (!errors.contains(errorMessage)) {
errors.add(errorMessage);
}
} catch (Exception e) {
if (LOG.isWarnEnabled()) {
LOG.warn("Unable to parse request", e);
}
String errorMessage = buildErrorMessage(e, new Object[]{});
if (!errors.contains(errorMessage)) {
errors.add(errorMessage);
}
}
}
然后,这是循环多部分项目的地方,包括文件和表单字段:
private void processUpload(HttpServletRequest request, String saveDir) throws FileUploadException, UnsupportedEncodingException {
for (FileItem item : parseRequest(request, saveDir)) {
if (LOG.isDebugEnabled()) {
LOG.debug("Found item " + item.getFieldName());
}
if (item.isFormField()) {
processNormalFormField(item, request.getCharacterEncoding());
} else {
processFileField(item);
}
}
}
这将在 FileUploadBase 中结束,在此实现中为每个项目:
FileItemStreamImpl(String pName, String pFieldName,
String pContentType, boolean pFormField,
long pContentLength) throws IOException {
name = pName;
fieldName = pFieldName;
contentType = pContentType;
formField = pFormField;
final ItemInputStream itemStream = multi.newInputStream();
InputStream istream = itemStream;
if (fileSizeMax != -1) {
if (pContentLength != -1
&& pContentLength > fileSizeMax) {
FileSizeLimitExceededException e =
new FileSizeLimitExceededException(
format("The field %s exceeds its maximum permitted size of %s bytes.",
fieldName, fileSizeMax),
pContentLength, fileSizeMax);
e.setFileName(pName);
e.setFieldName(pFieldName);
throw new FileUploadIOException(e);
}
istream = new LimitedInputStream(istream, fileSizeMax) {
@Override
protected void raiseError(long pSizeMax, long pCount)
throws IOException {
itemStream.close(true);
FileSizeLimitExceededException e =
new FileSizeLimitExceededException(
format("The field %s exceeds its maximum permitted size of %s bytes.",
fieldName, pSizeMax),
pCount, pSizeMax);
e.setFieldName(fieldName);
e.setFileName(name);
throw new FileUploadIOException(e);
}
};
}
stream = istream;
}
如您所见,它处理文件大小上限和请求大小上限的方式截然不同;
我查看了源代码以获得乐趣,但您确实可以确认(或纠正)这个假设,尝试调试 MultiPartRequestWrapper 以查看内部发生的事情是否是我认为正在发生的事情......祝你好运,玩得开心.