【问题标题】:400 (Bad Request) Error - Spring-boot File upload Using JQuery AJAX400(错误请求)错误 - 使用 JQuery AJAX 上传 Spring-boot 文件
【发布时间】:2017-03-01 18:01:30
【问题描述】:

我正在尝试使用 thymeleaf ajax 和 spring-boot 上传图片。我已经使用了我在 stackoverflow 和其他论坛上找到的大部分帖子,但我似乎确实有效。我在我的安全配置中添加了 CSRF,并将其包含在 ajax 上传脚本中,但仍然面临“400(错误请求)”错误。

异常错误

017-03-01 23:50:06.893 ERROR 58753 --- [nio-8080-exec-3] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.web.multipart.MultipartException: Could not parse multipart servlet request; nested exception is org.apache.commons.fileupload.FileUploadException: Stream closed] with root cause

java.io.IOException: Stream closed
    at org.apache.catalina.connector.InputBuffer.read(InputBuffer.java:372) ~[tomcat-embed-core-8.0.30.jar:8.0.30]
    at org.apache.catalina.connector.CoyoteInputStream.read(CoyoteInputStream.java:190) ~[tomcat-embed-core-8.0.30.jar:8.0.30]
    at java.io.FilterInputStream.read(FilterInputStream.java:133) ~[na:1.8.0_65]
    at org.apache.commons.fileupload.util.LimitedInputStream.read(LimitedInputStream.java:134) ~[commons-fileupload-1.3.2.jar:1.3.2]
    at org.apache.commons.fileupload.MultipartStream$ItemInputStream.makeAvailable(MultipartStream.java:999) ~[commons-fileupload-1.3.2.jar:1.3.2]
    at org.apache.commons.fileupload.MultipartStream$ItemInputStream.read(MultipartStream.java:903) ~[commons-fileupload-1.3.2.jar:1.3.2]
    at java.io.InputStream.read(InputStream.java:101) ~[na:1.8.0_65]
    at org.apache.commons.fileupload.util.Streams.copy(Streams.java:100) ~[commons-fileupload-1.3.2.jar:1.3.2]
    at org.apache.commons.fileupload.util.Streams.copy(Streams.java:70) ~[commons-fileupload-1.3.2.jar:1.3.2]
    at org.apache.commons.fileupload.MultipartStream.readBodyData(MultipartStream.java:593) ~[commons-fileupload-1.3.2.jar:1.3.2]

上传

<form id="upload-file-input" th:action="@{/uploadFile}" method="post" th:object="${picture}" enctype="multipart/form-data" class="form-inline inline new-item">
        <div th:replace="common/layout :: flash"></div>
        <fieldset>
            <legend> Upload Picture</legend>
        <div class="row">
            <div class="col s12 l8">
                <div class="file-wrapper">
                    <input type="file" id="file" name="uploadfile"/>
                    <span class="placeholder" data-placeholder="Choose an image...">Choose an image...</span>
                    <label for="file" class="button">Browse</label>
                    <span id="upload-file-message"></span>
                </div>
            </div>
            <button type="submit" class="btn btn-primary">Upload</button>
        </div>
        </fieldset>
        <div class="style16"></div>
    </form>

上传控制器

@RequestMapping(value = "/uploadFile", method = RequestMethod.POST)
    @ResponseBody
    public String uploadFile(@RequestParam("uploadfile") MultipartFile uploadfile) {

        try {
            // Get the filename and build the local file path
            String filename = uploadfile.getOriginalFilename();
            String directory = "/Sites/admissionsPortal/data";
            String filepath = Paths.get(directory, filename).toString();

            // Save the file locally
            BufferedOutputStream stream = new BufferedOutputStream(new FileOutputStream(new File(filepath)));
            stream.write(uploadfile.getBytes());
            stream.close();
        }
        catch (Exception e) {
            System.out.println(e.getMessage());
        }

        return "redirect:/cert_prog";
    } // method uploadFile

上传.js

var token = $("meta[name='_csrf']").attr("content");
$.ajaxSetup({
    beforeSend: function(xhr) {
        xhr.setRequestHeader('X-CSRF-TOKEN', token);
    }
});

var $form = $("#upload-file-input");
  $form.on("submit", function(e){
   e.preventDefault();
   $.ajax({
           url: $form.prop('action'),
           type: "POST",
           data: new FormData($("#upload-file-input")[0]),
           enctype: 'multipart/form-data',
           processData: false,
           contentType: false,
           cache: false,
           success: function () {
             // Handle upload success
             $("#upload-file-message").text("File succesfully uploaded");
           },
           error: function () {
             // Handle upload error
             $("#upload-file-message").text("File not uploaded (perhaps it's too much big)");
           }
         });
     });

【问题讨论】:

  • 你遇到过异常吗?
  • @MattClark 是的,我愿意
  • @MattClark 抛出 IOException

标签: java ajax spring spring-security jquery-file-upload


【解决方案1】:

你的错误的根本原因似乎是

嵌套异常是 org.springframework.web.multipart.MultipartException:无法解析多部分 servlet 请求

这让我相信您的服务器端正在按预期工作,但客户端未以预期格式发送数据。

您可以尝试将您的 ajax 调用更改为以下内容吗

// create a new form
var formData = new FormData();

// add your binary value to the file key
formData.append("file", fileBinary);


$.ajax({dataType : 'json',
    ...
    data : formData,                // add the form
    ...

那么在服务器端,上传的文件对象会出现在file参数中

public String uploadFile(@RequestParam("file") MultipartFile uploadfile) {

【讨论】:

  • 我将值添加到 formData.append("file", $('input[type="file"]')[0]).val();但报错 rg.springframework.web.multipart.MultipartException: The current request is not a multipart request –
【解决方案2】:

尝试这样获取formData

let uploadFile = $('#upload-file-input')[0];
let formData = new FormData(uploadFile);

ajaxdata属性中发送这个formData。

【讨论】:

    【解决方案3】:

    问题的原因是java.io.IOException: Stream closed。这很可能意味着在多部分请求解析开始之前,某些代码已经在HttpServletRequestInputStream 上调用了close()

    一个可能的罪魁祸首可能是 servlet Filter 的一个有缺陷的实现,它使用缓存装饰器包装了请求(大多数操作使用缓存的请求内容,除了用于多部分处理)并关闭输入在传递装饰请求以进行进一步处理之前进行流式传输。

    调试以查看在HttpServletRequestInputStream 上调用close 的内容应该会发现罪魁祸首。

    如果由于某种原因这很困难,您还可以尝试禁用任何第三方过滤器(各种验证、日志记录、监控过滤器等),看看问题是否仍然存在。

    【讨论】:

      猜你喜欢
      • 2015-04-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-03-23
      • 1970-01-01
      • 2014-12-31
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多