標籤:response art query his use ini java程式 other 失敗
項目裡的介面都是用springmvc寫的,其中在@requestmapping介面中定義了consumes="application/json",也就是該介面只接受ContentType為application/json的請求。
介面寫好用工具測試介面都是可以正常請求,但是在瀏覽器中用ajax請求就不行。
百度一下,原來在使用Ajax跨域請求時,如果設定Header的ContentType為application/json,會分兩次發送請求。第一次先發送Method為OPTIONS的請求到伺服器,這個請求會詢問伺服器支援哪些要求方法(GET,POST等),支援哪些要求標頭等等伺服器的支援情況。等到這個請求返回後,如果原來我們準備發送的請求符合伺服器的規則,那麼才會繼續發送第二個請求,否則會在Console中報錯。
為什麼在跨域的時候設定ContentType為application/json時會請求兩次?其實JQuery的文檔對此有做說明。
contentType (default: ‘application/x-www-form-urlencoded; charset=UTF-8‘)
Type: Boolean or String
When sending data to the server, use this content type. Default is "application/x-www-form-urlencoded; charset=UTF-8", which is fine for most cases. If you explicitly pass in a content-type to $.ajax(), then it is always sent to the server (even if no data is sent). As of jQuery 1.6 you can pass false to tell jQuery to not set any content type header. Note: The W3C XMLHttpRequest specification dictates that the charset is always UTF-8; specifying another charset will not force the browser to change the encoding. Note: For cross-domain requests, setting the content type to anything other than application/x-www-form-urlencoded, multipart/form-data, or text/plain will trigger the browser to send a preflight OPTIONS request to the server.
注意Note後面的描述,在跨域的時候,除了contentType為application/x-www-form-urlencoded,multipart/form-data或者text/plain外,都會觸發瀏覽器先發送方法為OPTIONS的請求。
比如說,你原來的請求是方法方法POST,如果第一個請求返回的結果Header中的Allow屬性並沒有POST方法,那麼第二個請求是不會發送的,此時瀏覽器控制台會報錯,告訴你POST方法並不被伺服器支援。
圖中箭頭指向的Allow就是伺服器返回的支援的方法。
不僅如此,如果想要用ContentType:application/json發送跨域請求,伺服器端還必須設定一個名為Access-Control-Allow-Headers的Header,將它的值設定為 Content-Type,表明伺服器能夠接收到前端發送的請求中的ContentType屬性並使用它的值。否則第二次請求也是發不出去的,瀏覽器console會報錯,並提示你伺服器沒有設定Access-Control-Allow-Headers。
對應到我java程式的filter過濾器裡是這樣
1 public class MyFilter implements Filter { 2 3 @Override 4 public void destroy() { 5 //System.out.println("過濾器銷毀"); 6 } 7 8 @Override 9 public void doFilter(ServletRequest request, ServletResponse response,10 HttpServletRequest httpRequest = (HttpServletRequest) request;11 String type=httpRequest.getMethod();12 13 if (type.toUpperCase().equals("OPTIONS")==true) {14 httpResponse.setHeader("Access-Control-Allow-Headers", "content-type, accept");15 httpResponse.setHeader("Access-Control-Allow-Methods", "POST");16 httpResponse.setStatus(200);17 httpResponse.setContentType("text/plain;charset=utf-8");18 httpResponse.setCharacterEncoding("utf-8");19 responseContentByte="{\"test\":\"OPTIONS\"}".getBytes();20 }21 }22 23 @Override24 public void init(FilterConfig arg0) throws ServletException {25 //System.out.println("過濾器初始化");26 }27 28 }
Ajax跨域之ContentType為application/json請求失敗的問題