繁体   English   中英

Spring MVC中包含多部分数据的POST请求

[英]POST request with multipart data in spring mvc

我正在客户端的Angular中使用ng-file-upload向Spring Boot Application发送文件(图像,文本等)。

我在Xampp中使用url“ localhost”运行客户端,而在Spring实例中使用url“ localhost:8080”单独运行。双方的cors已启用,其他所有请求均已成功接受。

客户端代码:

        Upload.upload({
        url: 'http://localhost:8080/file/upload',
        method:'POST',
            data: {
            uploadedPicture: file,
            uploadedFrom: 'recipe'
        },
    }).then(function(response) {
        $timeout(function() {
            $scope.result = response.data;
        });
    }, function(response) {
        if (response.status > 0) $scope.errorMsg = response.status + ': ' + response.data;
    }, function(evt) {
        $scope.progress = parseInt(100.0 * evt.loaded / evt.total);
    });

服务器端代码:

@CrossOrigin
@RequestMapping(method = RequestMethod.POST, value = "/file/upload")
public String handleFileUpload(@RequestParam("file") MultipartFile file,
                               RedirectAttributes redirectAttributes) {
    if (!file.isEmpty()) {
        try {
            Files.copy(file.getInputStream(), Paths.get(ROOT, file.getOriginalFilename()));
            redirectAttributes.addFlashAttribute("message",
                    "You successfully uploaded " + file.getOriginalFilename() + "!");
        } catch (IOException|RuntimeException e) {
            redirectAttributes.addFlashAttribute("message", "Failued to upload " + file.getOriginalFilename() + " => " + e.getMessage());
        }
    } else {
        redirectAttributes.addFlashAttribute("message", "Failed to upload " + file.getOriginalFilename() + " because it was empty");
    }

    return "redirect:/";
} 

我已经尝试通过使用正常工作的get方法将相同代码的get请求发送到相同资源来尝试cors,但是当我发送包含多部分表单数据(图像或任何其他文件)的post请求时,它将拒绝OPTIONS请求。

   OPTIONS http://localhost:8080/file/upload
   XMLHttpRequest cannot load http://localhost:8080/file/upload. Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost' is therefore not allowed access. The response had HTTP status code 403.

我也通过邮递员测试了此资源,并且上传了文件,没有错误。

编辑: 我尝试通过将http更改为https,它给出错误,因为选项https:// localhost:8080 / file / upload net :: ERR_TIMED_OUT_问题与它找不到所需的资源相同

对这个问题有什么想法吗?

查看您的错误消息,我看到:

不存在“ Access-Control-Allow-Origin”标头

您确定要添加正确的标题吗?

我们使用过滤器来确保所有请求都正确添加了这些标头:

  • 访问控制允许来源:*
  • 访问控制允许方法:POST,GET,OPTIONS,DELETE
  • 存取控制最大年龄:3600
  • 访问控制允许标题:x-requested-with

这是我们使用的Filter类:

SimpleCORSFilter.java

 @Component
 public class SimpleCORSFilter implements Filter {

        public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
            HttpServletResponse response = (HttpServletResponse) res;
            response.setHeader("Access-Control-Allow-Origin", "*");
            response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
            response.setHeader("Access-Control-Max-Age", "3600");
            response.setHeader("Access-Control-Allow-Headers", "x-requested-with");
            chain.doFilter(req, res);
        }

        public void init(FilterConfig filterConfig) {}

        public void destroy() {}

    }

只需将@CrossOrigin批注更改为:

@CrossOrigin(origins = "*", methods = {RequestMethod.POST, RequestMethod.OPTIONS}, allowedHeaders = {"Content-Type", "X-Requested-With", "accept", "Origin", "Access-Control-Request-Method", "Access-Control-Request-Headers"}, exposedHeaders = {"Access-Control-Allow-Origin", "Access-Control-Allow-Credentials"})

在chrome中尝试使用此扩展程序,可能会帮助您解决问题

https://chrome.google.com/webstore/detail/allow-control-allow-origi/nlfbmbojpeacfghkpbjhddihlkkiljbi?hl=fr

首先检查您的安全设置,因为您显然会得到403作为状态码。 也许您的重定向最终导致问题,请尝试不使用它。

这是一个代码示例,我前一段时间使用它来添加CORS-header:

@RequestMapping(value="/GetSomething", method = RequestMethod.GET, produces = "application/json;charset=UTF-8")
public ResponseEntity<String> getSomething() throws IOException {
    HttpHeaders responseHeaders = new HttpHeaders();
    //need for cross-domain requests
    responseHeaders.add("Access-Control-Allow-Origin", "*");
    //this one is needed, if your browser should send cookies
    responseHeaders.add("Access-Control-Allow-Credentials", "true");
    ...
    responseHeaders.setContentLength(resp.getBytes("UTF-8").length);
    return new ResponseEntity<String>(resp, responseHeaders, HttpStatus.OK);
}

编辑:删除会话参数

EDIT2:您可以检查POST请求中的代码是否真正在执行吗? 在功能中进行一些记录。 如果您的代码未执行,那么您显然会遇到安全设置问题,并且您的请求不会通过安全层。 CORS是基于客户端的功能,它只能在浏览器从服务器获取数据后阻止数据!

我在当前项目中之前曾遇到过这个问题,经过大量的RND和一些实验后,我发现问题出在内容类型上,每当有图像上传时,都会放置一个位置来上传内容类型。

我尚未对此进行测试,但是尝试通过替换附近的代码来让我知道...

            var fd = new FormData();
            fd.append('uploadedPicture', file);
            fd.append('uploadedFrom', 'recipe');

            Upload.upload({
                url: 'http://localhost:8080/file/upload',
                method: 'POST',
                data: fd,
                transformRequest: angular.identity,
                headers: {'Content-Type': undefined},
            }).then(function (response) {
                $timeout(function () {
                    $scope.result = response.data;
                });
            }, function (response) {
                if (response.status > 0)
                    $scope.errorMsg = response.status + ': ' + response.data;
            }, function (evt) {
                $scope.progress = parseInt(100.0 * evt.loaded / evt.total);
            });

试试这个后让我知道。

从Ajax调用返回重定向是没有意义的。 首先,确定问题是与表单发布有关还是与后续操作有关。 为此,如下更改控制器:

@CrossOrigin
@RequestMapping(method = RequestMethod.POST, value = "/file/upload")
@ResponseBody
public String handleFileUpload(@RequestParam("file") MultipartFile file) {

    String status = null;

    if (!file.isEmpty()) {
        try {
            Files.copy(file.getInputStream(), Paths.get(ROOT, file.getOriginalFilename()));
            status = "okay";

        } catch (IOException|RuntimeException e) {
            status = "error";  
        }
    } else {
        status = "error";
    }

    return "status"; // a literal string
}

我还要指出的是,从前端发送的参数与后端期望的参数不匹配。 您在前端的哪里指定一个名为“ file”的参数,该参数就是控制器要映射到指定的RequestParam的参数?

有问题的库在这里有一个使用Spring MVC的端到端示例:

https://github.com/danialfarid/ng-file-upload/wiki/spring-mvc-example

请注意参数名称在两侧如何匹配。

添加内容类型,请参阅此答案,可能对您有所帮助。 请求未找到ajax spring mvc和origins =“ / **”

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM