Spring MVC中的Ajax POST FormData抛出异常

时间:2018-06-21 18:50:50

标签: javascript java ajax spring-mvc

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

我有一个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库中的一个包含音频的对象。我也尝试使用简单的String,但是有相同的错误

还有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方法之前添加了这三行:

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

返回:

enter image description here

2 个答案:

答案 0 :(得分:1)

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

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>

答案 1 :(得分:0)

您遇到此异常

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) {

它应该可以工作