[英]Cross-platform Ajax upload not working
我正在 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 控制台中。
這里有一段帶有上傳的Javascript代碼的JSP:
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);
從彈簧控制器:
@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--
謎團越來越濃……
試試response.addHeader("Access-Control-Allow-Headers", "Content-Type, Content-Range, Content-Disposition, Content-Description");
而且我認為您也需要在方法中添加OPTIONS 。
我終於解決了我的問題。 事實證明,這不是真正的跨域問題,而是瀏覽器將 500 內部錯誤解釋為跨域訪問錯誤,這是在發生跨域調用和 500 時通常會發生的事情發生錯誤。 解決跨域錯誤時要記住的一點。
我真正的問題是一個簡單的 Spring 配置問題,但不知何故丟失的參數並沒有阻止代碼在我的本地 Tomcat 安裝上工作,我仍然不明白。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.