【问题标题】:Cross-platform Ajax upload not working跨平台 Ajax 上传不起作用
【发布时间】:2017-05-28 20:59:58
【问题描述】:

我正在 Spring Rest 服务上使用 Ajax 上传开发上传功能。它在开发服务器上运行良好,但是一旦在具有类似于生产的配置并且需要跨平台调用的集成服务器上,我就害怕了

XMLHttpRequest cannot load http://xxxxxxxxxx:7001/felixmetier/rest/upload/montants. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://yyyyyyy' is therefore not allowed access. The response had HTTP status code 500.

在我的 Javascript 控制台中。

这里有一段JSP与上传的Javascript代码:

  var xhr = new XMLHttpRequest();
  if ("withCredentials" in xhr) {
    xhr.withCredentials = true;
    xhr.open('POST', '<%=Environment.getServiceParameter("FELIX", "rest.service.saisieMontants.upload.url")%>', true);
  } else if (typeof XDomainRequest != "undefined") {
    xhr = new XDomainRequest();
    xhr.open('POST', '<%=Environment.getServiceParameter("FELIX", "rest.service.saisieMontants.upload.url")%>');
  } else {
    throw new Error('Accès cross-platform interdit sur ce navigateur. Utilisez un navigateur plus récent (IE 8+, Chrome 3+, Firefox 3.5+, Safari 4+).');
  }
  xhr.onload = function () {
    activateFormButtonsAndLinks();
    document.getElementById('fwkWaitingScreen').style.display = 'none';
    var response = this.responseText;
    var data = JSON.parse(response);

    if (data.status===1) {
        alert("Erreur générale lors du chargement (pas de mise à jour en BDD) : "+data.message);
    } else {
        var msg = "Chargement terminé.\n\nNb de lignes traitées : "+data.totLines+"\nNb de lignes déjà controlées : "+data.totControlled+"\nNb de lignes inexistantes en BDD : "+data.totIgnored

        if (data.status===2) {
            msg = msg + "\n\n"+data.totError+" erreur se sont produires lors du chargement. Lignes en erreur (max. "+data.maxError+" affichées) : "+data.errorLines
        } else {
            msg = msg + "\n\n"+"Chargement OK";
        }

        alert(msg);
    }

    var rechBouton = document.getElementsByName("recherche").item(0);

    doAction(rechBouton, '','rechercherbouton');
  }

  xhr.send(formData);

来自 Spring 控制器:

@Controller
public class MontantsUploadController {
...

    @RequestMapping(value = "/upload/montants", method = RequestMethod.POST)
    public ResponseEntity<?> upload(@RequestParam("file_up") MultipartFile file, HttpServletRequest request) {
        InputStream is;
        SaisieMontantsUploadRestResponse feedback = null;
        try {
            is = file.getInputStream();
            Reader reader = new InputStreamReader(is);

            feedback = parseImportedFile(reader, "guest", getLocale(request));
        } catch (IOException e) {
            feedback = new SaisieMontantsUploadRestResponse();
            feedback.setMessage("Impossible de lire le fichier attaché");
            feedback.setStatus(SaisieMontantsUploadRestResponse.STATUS_GENERAL_ERROR);
            log.error("Impossible de traiter le CSV", e);
        }

        backupFile(file);

        return new ResponseEntity<SaisieMontantsUploadRestResponse>(feedback, HttpStatus.OK);
    }
...
}

来自我的 web.xml:

<filter>
    <filter-name>CORS</filter-name>
    <filter-class>fr.xxxx.felix.ejb.restjson.filter.CorsFilter</filter-class>
</filter>

<!-- Applying the CORS Filter to All REST URL -->
<filter-mapping>
    <filter-name>CORS</filter-name>
    <url-pattern>/rest/*</url-pattern>
</filter-mapping>

这里是过滤器的代码:

public class CorsFilter extends OncePerRequestFilter {
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
            throws ServletException, IOException {
        response.addHeader("Access-Control-Allow-Origin", "*");
        response.addHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE");
        response.addHeader("Access-Control-Allow-Headers", "Content-Type");
        response.addHeader("Access-Control-Max-Age", "30");

        filterChain.doFilter(request, response);
    }
}

我正在使用 Java 7、Tomcat 7 和 Spring 3.0.4。

编辑:我刚刚看到,如果我登录(我无法在该服务器上调试)request.getHeader("Access-Control-Request-Method"),它是空的。但是request.getMethod() 返回“POST”。这正常吗?

编辑 2: 我的 rest 调用使用 POST 方法,具有 multipart/form-data 内容类型且没有自定义标头,因此不需要预检调用。无论如何,我通过添加自定义标头并在我的 Access-Control-Allow-Headers 响应标头中对其进行授权来强制进行预检调用。现在,我可以在浏览器的网络控制台中看到 2 个调用。奇怪的是:我的预检 OPTIONS 调用没有任何问题通过,但我的 POST 调用仍然导致“请求的资源上不存在'Access-Control-Allow-Origin'标头”。我真的不明白。

编辑 3: 好的,现在我们到了某个地方。在跨域情况下,浏览器似乎将来自服务器的 500 错误解释为跨域错误。当我查看 localhost.log 时,我实际上看到了一个异常:

org.springframework.web.bind.MissingServletRequestParameterException: Required MultipartFile parameter 'file_up' is not present
        at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter$ServletHandlerMethodInvoker.raiseMissingParameterException(AnnotationMethodHandlerAdapter.java:715)
        at org.springframework.web.bind.annotation.support.HandlerMethodInvoker.resolveRequestParam(HandlerMethodInvoker.java:511)
        at org.springframework.web.bind.annotation.support.HandlerMethodInvoker.resolveHandlerArguments(HandlerMethodInvoker.java:340)
        at org.springframework.web.bind.annotation.support.HandlerMethodInvoker.invokeHandlerMethod(HandlerMethodInvoker.java:171)
        at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.invokeHandlerMethod(AnnotationMethodHandlerAdapter.java:427)
        at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.handle(AnnotationMethodHandlerAdapter.java:415)
        at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:788)
        at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:717)
        at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:644)
        at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:560)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:647)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:728)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
        at fr.xxxxx.felix.ejb.restjson.filter.CorsFilter.doFilterInternal(CorsFilter.java:77)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:76)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
        at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:222)
        at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123)
        at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472)
        at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:171)
        at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:99)
        at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:936)
        at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
        at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:407)
        at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1004)
        at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:589)
        at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:310)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
        at java.lang.Thread.run(Thread.java:745)

现在的问题是:我在 Chrome 的网络视图中的请求中可以看到名为“file_up”的多部分文件,所以我仍然不明白为什么它不起作用。

请求负载:

------WebKitFormBoundaryi7iVj0nFvRL8zcuy
Content-Disposition: form-data; name="file_up"; filename="test_SAISIE_DES_MONTANTS.csv"
Content-Type: application/vnd.ms-excel


------WebKitFormBoundaryi7iVj0nFvRL8zcuy--

谜团越来越浓……

【问题讨论】:

  • 它看起来很像一个已识别的问题,但即使我添加了 multipartResolver 和 multipartFilter,它仍然无法正常工作。但我正在取得进展。

标签: javascript java spring file-upload cross-domain


【解决方案1】:

试试
response.addHeader("Access-Control-Allow-Headers", "Content-Type, Content-Range, Content-Disposition, Content-Description");

我认为您也需要在方法中添加 OPTIONS

【讨论】:

  • 我在“Access-Control-Allow-Headers”标头中添加了“Content-Range, Content-Disposition, Content-Description”,在“Access-Control-Allow-Methods”中添加了“OPTIONS”,但我仍然遇到同样的错误。
【解决方案2】:

我终于解决了我的问题。事实证明这不是一个真正的跨域问题,而是 浏览器将 500 内部错误解释为跨域访问错误,这通常会在跨域访问时发生。发生域调用并发生 500 错误。处理跨域错误时要牢记的一点。

我真正的问题是一个简单的 Spring 配置问题,但不知何故,缺少的参数并没有阻止代码在我的本地 Tomcat 安装上运行,我仍然不明白。

【讨论】:

猜你喜欢
  • 2012-03-03
  • 1970-01-01
  • 1970-01-01
  • 2017-03-07
  • 2011-02-27
  • 2018-05-09
  • 1970-01-01
  • 1970-01-01
  • 2011-08-03
相关资源
最近更新 更多