天天看點

解決AJAX跨域:1、利用JSONP;2、JS設定Header

一、利用JSONP:

  首先來看看在頁面中如何使用jQuery的ajax解決跨域問題的簡單版:

  這樣寫是完全沒有問題的,起先error的處理函數中僅僅是alert(“error”),為了進一步弄清楚是什麼原因造成了錯誤,故将處理函數變為上面的實作方式。最後一行alert回報parsererror問題。百思不得其解,原因是jsonp的格式與json格式有着細微的差别,是以在server端的代碼上稍稍有所不同。

  比較一下json與jsonp格式的差別:

  JSON格式:

  JSONP格式:

  看出來差別了吧,在url中callback傳到背景的參數是什麼callback就是什麼,jsonp比json外面有多了一層callback()。這樣就知道怎麼處理它了,于是修改背景代碼。

  背景java代碼最終如下:

  注意:這裡需要先将查詢結果轉換為json格式,然後用參數callback在json外面再套一層,就變成了jsonp。指定資料類型為jsonp的ajax就可以做進一步處理了。

  雖然這樣解決了跨域問題,還是回顧下造成parsererror的原因。原因在于盲目的把json格式的資料當做jsonp格式的資料讓ajax處理,造成了這個錯誤,此時server端代碼是這樣的:

二、JS設定Header,實作跨域通路:

  受浏覽器的同源政策限制,JavaSript隻能請求本域内的資源。跨域資源共享(Cross-Origin Resource Sharing, CORS)是為解決Ajax技術難實作跨域問題而提出的一個規範,這個規範試着從根本上解決安全的跨域資源共享問題。在此之前,解決此類問題的途徑往往是伺服器代理、JSONP等,治标不治本。目前基本所有浏覽器都已經支援該規範。

  一個域是由schema、host、port三者共同組成,與路徑無關。所謂跨域,是指在http://example-foo.com/域上通過XMLHttpRequest對象調用http://example-bar.com/域上的資源。CORS約定伺服器端和浏覽器在HTTP協定之上,通過一些額外HTTP頭部資訊,進行跨域資源共享的協商。伺服器端和浏覽器都必需遵循規範中的要求。

  CORS把HTTP請求分成兩類,不同類别按不同的政策進行跨域資源共享協商。

1. 簡單跨域請求。

  當HTTP請求出現以下兩種情況時,浏覽器認為是簡單跨域請求:

1). 請求方法是GET、HEAD或者POST,并且當請求方法是POST時,Content-Type必須是application/x-www-form-urlencoded, multipart/form-data或着text/plain中的一個值。

2). 請求中沒有自定義HTTP頭部。

  對于簡單跨域請求,浏覽器要做的就是在HTTP請求中添加Origin Header,将JavaScript腳本所在域填充進去,向其他域的伺服器請求資源。伺服器端收到一個簡單跨域請求後,根據資源權限配置,在響應頭中添加Access-Control-Allow-Origin

Header。浏覽器收到響應後,檢視Access-Control-Allow-Origin Header,如果目前域已經得到授權,則将結果傳回給JavaScript,否則浏覽器忽略此次響應。

2. 帶預檢(Preflighted)的跨域請求。

  當HTTP請求出現以下兩種情況時,浏覽器認為是帶預檢(Preflighted)的跨域請求:

1). 除GET、HEAD和POST(only with application/x-www-form-urlencoded, multipart/form-data, text/plain Content-Type)以外的其他HTTP方法。

2). 請求中出現自定義HTTP頭部。

  帶預檢(Preflighted)的跨域請求需要浏覽器在發送真實HTTP請求之前先發送一個OPTIONS的預檢請求,檢測伺服器端是否支援真實請求進行跨域資源通路,真實請求的資訊在OPTIONS請求中通過Access-Control-Request-Method

Header和Access-Control-Request-Headers

Header描述,此外與簡單跨域請求一樣,浏覽器也會添加Origin

Header。伺服器端接到預檢請求後,根據資源權限配置,在響應頭中放入Access-Control-Allow-Origin

Header、Access-Control-Allow-Methods和Access-Control-Allow-Headers

Header,分别表示允許跨域資源請求的域、請求方法和請求頭。此外,伺服器端還可以加入Access-Control-Max-Age

Header,允許浏覽器在指定時間内,無需再發送預檢請求進行協商,直接用本次協商結果即可。浏覽器根據OPTIONS請求傳回的結果來決定是否繼續發送真實的請求進行跨域資源通路。這個過程對真實請求的調用者來說是透明的。

  XMLHttpRequest支援通過withCredentials屬性實作在跨域請求攜帶身份資訊(Credential,例如Cookie或者HTTP認證資訊)。浏覽器将攜帶Cookie

Header的請求發送到伺服器端後,如果伺服器沒有響應Access-Control-Allow-Credentials

Header,那麼浏覽器會忽略掉這次響應。

  這裡讨論的HTTP請求是指由Ajax XMLHttpRequest對象發起的,所有的CORS HTTP請求頭都可由浏覽器填充,無需在XMLHttpRequest對象中設定。以下是CORS協定規定的HTTP頭,用來進行浏覽器發起跨域資源請求時進行協商:

1. Origin。HTTP請求頭,任何涉及CORS的請求都必需攜帶。

2. Access-Control-Request-Method。HTTP請求頭,在帶預檢(Preflighted)的跨域請求中用來表示真實請求的方法。

3. Access-Control-Request-Headers。HTTP請求頭,在帶預檢(Preflighted)的跨域請求中用來表示真實請求的自定義Header清單。

4.

Access-Control-Allow-Origin。HTTP響應頭,指定伺服器端允許進行跨域資源通路的來源域。可以用通配符*表示允許任何域的JavaScript通路資源,但是在響應一個攜帶身份資訊(Credential)的HTTP請求時,Access-Control-Allow-Origin必需指定具體的域,不能用通配符。

5. Access-Control-Allow-Methods。HTTP響應頭,指定伺服器允許進行跨域資源通路的請求方法清單,一般用在響應預檢請求上。

6. Access-Control-Allow-Headers。HTTP響應頭,指定伺服器允許進行跨域資源通路的請求頭清單,一般用在響應預檢請求上。

7. Access-Control-Max-Age。HTTP響應頭,用在響應預檢請求上,表示本次預檢響應的有效時間。在此時間内,浏覽器都可以根據此次協商結果決定是否有必要直接發送真實請求,而無需再次發送預檢請求。

8. Access-Control-Allow-Credentials。HTTP響應頭,凡是浏覽器請求中攜帶了身份資訊,而響應頭中沒有傳回Access-Control-Allow-Credentials: true的,浏覽器都會忽略此次響應。

  總結:隻要是帶自定義header的跨域請求,在發送真實請求前都會先發送OPTIONS請求,浏覽器根據OPTIONS請求傳回的結果來決定是否繼續發送真實的請求進行跨域資源通路。是以複雜請求肯定會兩次請求服務端。

  js 端的ajax請求:

  服務端的action:

總結:

1、JSONP格式:(1)url加:&callback=?;type變為"jsonp";(2)伺服器端傳回資料要為jsonp格式,即:out.print(callback + "(" + json + ")");要套一層callback()

2、伺服器Action層增加Header頭資訊