当前位置: 首页 > 知识库问答 >
问题:

处理MaxUploadSizeExceedException无法停止上载文件

许彭祖
2023-03-14

我想检查上传文件的大小并防止文件完全加载到内存中。我使用的是通用多部分文件。上传的文件将被处理并保存在数据库中。AbstractCoupleU反射控制器类处理包含文件的传入请求:

public abstract class AbstractCoupleUploadController<T extends Serializable> extends RemoteServiceServlet implements ServletContextAware,
        UploadServlet<WorkshopHistoryModel>
{
    ...

    @RequestMapping(method={RequestMethod.GET,RequestMethod.POST})
    public ModelAndView handleRequest(@RequestParam("firstFile") CommonsMultipartFile firstFile,
            @RequestParam("secondFile") CommonsMultipartFile secondFile, HttpServletRequest request, HttpServletResponse response)
    {
        synchronized(this)
        {
            initThreads();
            perThreadRequest.set(request);
            perThreadResponse.set(response);
        }

        handleUpload(firstFile,secondFile,request,response);
        response.getWriter().flush();
        response.flushBuffer();
        return null;
    }

    private void handleUpload(CommonsMultipartFile firstFile, CommonsMultipartFile secondFile, HttpServletRequest request,
        HttpServletResponse response) throws IOException
    {
        response.setContentType("text/html");
        if(firstFile.getSize() == 0 || secondFile.getSize() == 0)
        {
            response.getWriter().print(AppConstants.UPLOAD_ZERO_SIZE_FILE);
            return;
        }

        // other validations
        // uploading:
        try
        {
            String content = request.getParameter(CoupleUploadPanel.CONTENT);
            T model = deserialize(content);
            UploadResultModel resultModel = upload(model,firstFile,secondFile); // it's implemented in UploadFileServletImpl 
            if(resultModel.hasCriticalError())
            {
                response.getWriter().print(AppConstants.UPLOAD_FAIL + "," + String.valueOf(resultModel.getWorkshopHistoryId()));
            }
            else
            {
                response.getWriter().print(AppConstants.UPLOAD_SUCCESS + "," + String.valueOf(resultModel.getWorkshopHistoryId()));
            }
        }
        catch(ProcessRequestException e)
        {
           // write upload error description in response.getWriter()
        }
        catch(Exception e)
        {
            e.printStackTrace();
            response.getWriter().print(AppConstants.UPLOAD_UNKOWN_ERROR);
        }
    }

    ...
}

我的app-servlet中有一个多部分解析器bean.xml(file.upload.max_size=9437184),还有一个maxUploadSizeExceededExceptionHandler bean,用于处理UploadSizeExceededExceptions:

 <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
     <property name="maxUploadSize" value="${file.upload.max_size}" />
 </bean>
 <bean id="maxUploadSizeExceededExceptionHandler" class="com.insurance.ui.server.uploadfile.MaxUploadSizeExceededExceptionHandler">
     <property name="order" value="1"/>
 </bean>

My maxUploadSizeExceededExceptionHandler:

public class MaxUploadSizeExceededExceptionHandler implements HandlerExceptionResolver, Ordered
{
    private int order;

    @Override
    public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
    {
        if(ex instanceof MaxUploadSizeExceededException)
        {
            try
            {
                response.getWriter().print(ErrorConstants.UPLOAD_SIZE_EXCEED + "," + (((MaxUploadSizeExceededException) ex).getMaxUploadSize()/(1024*1024)));
                response.getWriter().flush();
                response.flushBuffer();
                return new ModelAndView();
            }
            catch(IOException e)
            {
            }
        }
        return null;
    }
    ...
}

当我上传一个非常大的文件(超过${file.upload.max_size},大约700MB)时,CommonsMultipartResolver立即抛出MaxUploadSizeExceededException,我正在捕捉并处理它(在response.getWriter()中写入)。但是我的问题是:我的浏览器上传进度条显示文件仍在上传!!为什么?

更新:我正在使用:

  • Spring-*-3.0.5.释放
  • commons-fileupload-1.1.1

并尝试:

  • Spring-*-3.1.2.释放
  • commons-fileupload-1.3

和我的AS:

  • Tomcat 6(开发中)
  • JBoss 7(生产中)

更新2:在客户端,我用的是GWT(我觉得没关系):

通过单击提交请求按钮开始上传:

@UiHandler("submitRequestButton")
public void submitRequestButtonClick(ClickEvent event)
{
    try
    {
        // some validation
        submitRequestButton.setEnabled(false);
        uploadPanel.upload(model.getWorkshopHistoryModel()); // uploadPanel is from the CoupleUploadPanel type
    }
    catch(ValidationException exception)
    {
        // handle validation errors
    }
    catch(SerializationException e)
    {
        // handle serialization errors
    }
}

我有一个用于上传的CoupleUpload面板小部件(两个文件):

public class CoupleUploadPanel<T extends Serializable> extends FormPanel
{
    public final static String CONTENT = "content";
    private static final String FIRST_FILE = "firstFile";
    private static final String SECOND_FILE = "secondFile";

    private Hidden contentInput;
    private FileUpload firstFileUploadInput;
    private FileUpload secondFileUploadInput;
    private SerializationStreamFactory factory;

    public CoupleUploadPanel(UploadServletAsync<T> factory)
    {
        this(null,factory);
    }

    public CoupleUploadPanel(String url, UploadServletAsync<T> factory)
    {
        this.factory = (SerializationStreamFactory) factory;
        if(url != null)
        {
            setAction(url);
        }
        init();
    }
    public CoupleUploadPanel(String target, String url, UploadServletAsync<T> factory)
    {
        super(target);
        this.factory = (SerializationStreamFactory) factory;
        if(url != null)
        {
            setAction(url);
        }
        init();
    }

    private void init()
    {
        setMethod("POST");
        setEncoding(ENCODING_MULTIPART);
        firstFileUploadInput = new FileUpload();
        firstFileUploadInput.setName(CoupleUploadPanel.FIRST_FILE);
        secondFileUploadInput = new FileUpload();
        secondFileUploadInput.setName(CoupleUploadPanel.SECOND_FILE);
        contentInput = new Hidden();
        contentInput.setName(CONTENT);
        VerticalPanel panel = new VerticalPanel();
        panel.add(firstFileUploadInput);
        panel.add(secondFileUploadInput);
        panel.add(contentInput);
        add(panel);
    }

    public void upload(T input) throws SerializationException
    {
        contentInput.setValue(serialize(input));
        submit();
    }

    private String serialize(T input) throws SerializationException
    {
        SerializationStreamWriter writer = factory.createStreamWriter();
        writer.writeObject(input);
        return writer.toString();
    }
}

我们应该将UploadServletAsync传递给CoupleUploadPanel构造函数。UploadServletAsync和UploadServlet接口:

public interface UploadServletAsync<T extends Serializable> 
{
    void upload(T model, AsyncCallback<Void> callback);
}

public interface UploadServlet<T extends Serializable> extends RemoteService
{
    void upload(T model);
}

所以上传面板将以这种方式实例化:

uploadPanel= new CoupleUploadPanel<WorkshopHistoryModel>((UploadFileServletAsync) GWT.create(UploadFileServlet.class));
uploadPanel.setAction(UploadFileServlet.URL);

在uploadPanel中添加了一个SubmitCompleteHandler(当提交完成并将结果传递给客户端时,将调用onSumbitComplete()):

uploadPanel.addSubmitCompleteHandler(new SubmitCompleteHandler()
{

    @Override
    public void onSubmitComplete(SubmitCompleteEvent event)
    {
        String s = event.getResults(); //contains whatever written by response.getWriter() 
        if(s == null)
        {
            // navigate to request list page
        }
        else
        {
            String[] response = s.split(",");
            // based on response: 
            // show error messages if any error occurred in file upload
            // else: navigate to upload result page
        }
    }
});

上传FileServlet和上传FileServletAsync接口:

public interface UploadFileServlet extends UploadServlet<WorkshopHistoryModel>
{
    String URL = "**/uploadFileService.mvc";
}

public interface UploadFileServletAsync extends UploadServletAsync<WorkshopHistoryModel>
{
    public static final UploadFileServletAsync INSTANCE = GWT.create(UploadFileServlet.class);
}

在服务器端:UploadFileServletImpl 扩展了 AbstractCoupleUploadController 并实现了 upload() 方法(上传过程):

@RequestMapping(UploadFileServlet.URL)
public class UploadFileServletImpl extends AbstractCoupleUploadController<WorkshopHistoryModel>
{
    ...

    @Override
    protected UploadResultModel upload(WorkshopHistoryModel model, MultipartFile firstFile, MultipartFile secondFile)
            throws ProcessRequestException
    {
        return workshopHistoryService.submitList(model.getWorkshop(),firstFile,secondFile);
    }

    ...
}

共有3个答案

钱繁
2023-03-14

作为第一次尝试,我会在MaxUploadSizeExceededExceptionHandler中调用response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR)。

然后我会检查一两个 SO 问题,看看它们是否包含一些我可以尝试的有用信息。

如果这没有帮助,我会调查 GwtUpload 的来源,看看他们是如何实现它的(或者只是开始使用他们的实现)。

汪弘盛
2023-03-14

我们使用以下方法:

public class MultipartResolver extends CommonsMultipartResolver {

public MultipartHttpServletRequest resolveMultipart(HttpServletRequest request) throws MultipartException {
    String encoding = determineEncoding(request);
    FileUpload fileUpload = prepareFileUpload(encoding);

    try {
        List fileItems = ((ServletFileUpload) fileUpload).parseRequest(request);
        MultipartParsingResult parsingResult = parseFileItems(fileItems, encoding);
        return new DefaultMultipartHttpServletRequest(
                request, parsingResult.getMultipartFiles(), parsingResult.getMultipartParameters(), parsingResult.getMultipartParameterContentTypes());
    } catch (FileUploadBase.SizeLimitExceededException ex) {
        throw new MaxUploadSizeExceededException(fileUpload.getSizeMax(), ex);
    }
    catch (FileUploadException ex) {
        throw new MultipartException("Could not parse multipart servlet request", ex);
    }
}

public void cleanupMultipart(MultipartHttpServletRequest request) {
    super.cleanupMultipart(request);
}    

public void setFileSizeMax(long fileSizeMax) {
    getFileUpload().setSizeMax(-1);
    getFileUpload().setFileSizeMax(fileSizeMax);
}

}

百里伟
2023-03-14

好吧,afaik Spring(一个servlet和一些过滤器)不观察上传过程,只处理完成过程的结果。这是因为上传是由Tomcat自己处理的(提示:在< code>web.xml中有一个上传大小限制选项)。所以上传失败(Spring不会注意到)或者上传一个太大的文件是有可能的。只有当第二次发生时,特定的过滤器/拦截器才能拒绝该进程。

在我上次的设置中,我在Tomcat前面使用Ngin x作为代理:

  1. 如果你的浏览器发送实际的文件大小(现代浏览器发送,至少是IE7?或IE8?没有),那么如果大小超过定义的限制,Nginx将发送500。
  2. 我不是100%确定:如果上传的大小超过指定的限制,Nginx也会发送500。这也将取消与Tomcat的底层连接。
 类似资料:
  • 我需要停止处理接口上的Spring MVC注释,但应该创建此接口的bean。e、 我与MVC REST注释共享了Api接口,Controller实现了这个Api。在另一个项目中,我基于接口创建了REST客户端(通过处理注释)。但当我创建客户机时,Spring将接口视为返回类型,并在其中进行流程注释。所以,我需要在创建REST客户端时停止注释处理,但对于控制器注释应该可以工作(现在它们可以工作了)。

  • 我有最奇怪的FTP问题。重新启动后,windows命令行ftp程序立即运行良好。 重新启动操作系统(64位Win7),一切都好起来了。 我已经禁用了windows防火墙,因为许多讨论都围绕这一点。无论windows防火墙处于打开或关闭状态,该行为都是相同的。 我已经尝试切换PASV模式,并且再次,无论是否发送被动,行为都是相同的。 有任何想法,如何运行一个程序可能导致命令行ftp变得无法发送文件,

  • 我已经在NIFI中导入了一个新的OPCUA包。这里 而且这个处理器读数良好超过一天,但后来我得到了这个错误: 如果我使用Nifi重新启动StandardOPCUAService,我可以再次接收数据。我如何解决这个问题?如何自动重启服务?

  • 我正在尝试上载文件,但无法工作: 有用信息:运行IIS Express(使用PHP5.3)-Windows 7 Professional 32位 代码: move_uploaded_file($_FILES[图像][名称],/图像/。$_FILES["Imagem"]["name"])或die("Error:".print_r($_FILES)); 它打印:数组([imagem]= 我确信路径是正

  • 我正在使用CKEditor插件将图像上传到我的OpenShift应用程序,但该应用程序不会上传文件。它在本地运行良好,但我无法确定是什么导致了这个问题。它似乎找不到目录。 == {err:{[Error: ENOENT, open'/var/lib/openShift/57cdb2770c1e660d0b000003/app-root/runtime/repo/路由来/.../Public/上传/

  • 我需要使用以下两种情况来处理大文件:(1)从文件目录中拉取并推送到FTP(2)从一个FTP中拉取,推送到另一个FTP 我正在创建一个java maven依赖项目,它使用camel组件来处理上述文件传输用例,所以我决定使用org.apache.camel.main。主类开始我的路线,但问题是即使文件处理成功,我的程序也没有关闭。我在某个地方读到,使用“System.exit()”可以解决问题,但问题