【问题标题】:Ajax POST FormData throw exception in Spring MVCSpring MVC中的Ajax POST FormData抛出异常
【发布时间】:2018-06-21 18:50:49
【问题描述】:

昨天我遇到了类似的问题,Ajax POST 方法返回 405 错误,这是由 csrf 令牌引起的。有人帮我解决了这个问题,但现在我无能为力了。

我有一个 Ajax POST 请求:

$(document).ready(function(){
    var mic, recorder, soundFile;
    setup();
})


function setup() {
  mic = new p5.AudioIn();
  mic.start();
  recorder = new p5.SoundRecorder();
  recorder.setInput(mic);
  soundFile = new p5.SoundFile();
}

function toggleRecording(e) {
    if (e.classList.contains("recording")) {
        recorder.stop();    
        e.classList.remove("recording"); 
        sendAudioToServer(soundFile)
    } else {
        e.classList.add("recording");
        recorder.record(soundFile);
    }
}

function sendAudioToServer(soundFile)
{
    var data = new FormData();
    data.append('file', soundFile);
    $.ajax({
        method: 'POST',
        enctype: 'multipart/form-data',
        url: '/recognizeCommand',
        data: data,
        processData: false,
        contentType: false,
        success: function(data) {
          alert("works!");
        },    
        error: function(xhr, ajaxOptions, thrownError) {
            alert(xhr.status);
            alert(thrownError);
        }
    })
}

soundFile 是 p5.js 库中包含音频的对象。我也尝试使用简单的字符串,但有同样的错误

还有一个 Spring MVC 中的控制器:

@RequestMapping(value = "/recognizeCommand", method = RequestMethod.POST)
    public @ResponseBody String recognizeCommand(@RequestParam("file") MultipartFile multipartFile) {
        try {
            SpeechRecognitionApplication.logger.info("BEFORE: " + multipartFile);
            byte[] bytes = multipartFile.getBytes();
            SpeechRecognitionApplication.logger.info(bytes);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return "finish";
    }

当我发送这个 Ajax 请求时,它会抛出错误 400,并且 Spring 中有异常:

org.springframework.web.multipart.support.MissingServletRequestPartException: Required request part 'file' is not present
    at org.springframework.web.method.annotation.RequestParamMethodArgumentResolver.handleMissingValue(RequestParamMethodArgumentResolver.java:199) ~[spring-web-5.0.5.RELEASE.jar:5.0.5.RELEASE]
    at org.springframework.web.method.annotation.AbstractNamedValueMethodArgumentResolver.resolveArgument(AbstractNamedValueMethodArgumentResolver.java:112) ~[spring-web-5.0.5.RELEASE.jar:5.0.5.RELEASE]
    at org.springframework.web.method.support.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:124) ~[spring-web-5.0.5.RELEASE.jar:5.0.5.RELEASE]
    at org.springframework.web.method.support.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:161) [spring-web-5.0.5.RELEASE.jar:5.0.5.RELEASE]
    at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:131) [spring-web-5.0.5.RELEASE.jar:5.0.5.RELEASE]
    at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:102) [spring-webmvc-5.0.5.RELEASE.jar:5.0.5.RELEASE]
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:877) [spring-webmvc-5.0.5.RELEASE.jar:5.0.5.RELEASE]
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:783) [spring-webmvc-5.0.5.RELEASE.jar:5.0.5.RELEASE]
    at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) [spring-webmvc-5.0.5.RELEASE.jar:5.0.5.RELEASE]
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:991) [spring-webmvc-5.0.5.RELEASE.jar:5.0.5.RELEASE]
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:925) [spring-webmvc-5.0.5.RELEASE.jar:5.0.5.RELEASE]
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:974) [spring-webmvc-5.0.5.RELEASE.jar:5.0.5.RELEASE]
    at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:877) [spring-webmvc-5.0.5.RELEASE.jar:5.0.5.RELEASE]

重要的是,当我使用邮递员测试端点并发送一些文件作为参数时,它可以正常工作。

我知道这个论坛上有类似的帖子,但我认真地检查了每个帖子,尝试了所有解决方案,但没有任何帮助。 我相信你们中的一些人会知道如何解决这个问题。

编辑 在 ajax post 方法之前添加了这 3 行:

data.append('file', "example");
console.log("file: " + data.get("file"));
console.log(data);

返回:

【问题讨论】:

  • 我相信你的问题在于 contentType = false;
  • 当我删除它时,状态为 500:org.springframework.web.multipart.MultipartException: Current request is not a multipart request
  • 我尝试了所有与 ajax 参数的组合,但没有任何效果。
  • 声音文件的类型是什么。
  • p5.SoundFile();

标签: javascript java ajax spring-mvc


【解决方案1】:

我猜问题不在于弹簧控制器,而是文件传递给请求的方式。为确保文件通过,您可以登录浏览器检查文件是否存在:

console.log("file" + data.get("file"));

你能展示你用来从输入中获取文件的代码吗?

编辑: 你能用这个简单的文件上传表单来测试你的端点吗?

<!DOCTYPE html>
<html>
<head>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
    <script>

        function handleFileSelect() {
            var data = new FormData();
            input = document.getElementById('fileinput');
            data.append('file', input.files[0]);
            console.log("file" + data.get("file"));
            $.ajax({
                method: 'POST',
                enctype: 'multipart/form-data',
                url: 'http://localhost:8080/test/recognizeCommand',
                data: data,
                processData: false,
                contentType: false,
                success: function (data) {
                    alert("works!");
                },
                error: function (xhr, ajaxOptions, thrownError) {
                    alert(xhr.status);
                    alert(thrownError);
                }
            });
        }
    </script>
</head>
<body>

<input type="file" id="fileinput"/>
<input type='button' id='btnLoad' value='Test' onclick='handleFileSelect();'>

</body>
</html>

【讨论】:

  • 返回:file[object Object]
  • 请用我编辑的答案进行测试。用你的替换网址
  • 所以问题出在 p5.SoundFile() 上,它可能不是有效的多部分文件。您的后端工作正常
  • 好吧,所以我必须找到其他一些库或深入查看文档以找到解决方案
【解决方案2】:

你得到了这个异常

org.springframework.web.multipart.support.MissingServletRequestPartException: Required request part 'file' is not present

如果你看看这部分代码

public @ResponseBody String recognizeCommand(@RequestParam("file") MultipartFile multipartFile)

您正在使用@RequestParam,因此您必须将代码更改为

@RequestMapping(value = "/recognizeCommand", method = RequestMethod.POST, consumes = { "multipart/form-data" })
public @ResponseBody String recognizeCommand(@RequestPart("file") MultipartFile multipartFile) {

它应该可以工作

【讨论】:

  • 可能 soundFile 不是有效的 MultipartFile,尝试使用其他文件
  • 如果我将简单的字符串传递给 FormData 这是同样的问题
  • 还是同样的问题
  • 你不能在多部分中传递一个简单的字符串,你必须使用这样的东西... formData.append('test', new Blob(["HELLO!!!"], { type: “文本/纯文本”})); ....我认为您的文件不是有效的 MultipartFile
猜你喜欢
  • 2013-02-09
  • 2015-05-03
  • 2020-01-25
  • 2011-04-24
  • 1970-01-01
  • 2023-03-24
  • 2016-09-10
  • 2018-07-27
  • 1970-01-01
相关资源
最近更新 更多