AJAX 跨域详解
一、什么是 AJAX 跨域問題
同源策略規(guī)定,AJAX 請(qǐng)求(XMLHttpRequest)只能發(fā)給同源的網(wǎng)址,否則就會(huì)出錯(cuò)。所謂的同源策略是指 3 個(gè)相同:協(xié)議相同、域名相同、端口相同。
比如 http://www.example.com/index.html 這個(gè)網(wǎng)址,協(xié)議是http ,域名是 www.example.com,端口是默認(rèn)的 80。如果你在這個(gè)網(wǎng)站上使用 AJAX 發(fā)送 http://www.example1.com/index.html 請(qǐng)求,就會(huì)出錯(cuò),因?yàn)橛蛎煌?/p>
AJAX 跨域的根本原因是瀏覽器不允許這么做(不是服務(wù)端的問題),瀏覽器限制 AJAX 跨域請(qǐng)求的目的是為了保證用戶信息的安全,防止數(shù)據(jù)被惡意獲取。
二、JSONP 解決跨域問題
JSONP 如何解決跨域問題?
- AJAX 請(qǐng)求非同源資源會(huì)發(fā)生跨域問題,但是有的 HTML 標(biāo)簽支持非同源請(qǐng)求,舉例來說:<img src=""> 與 <script src=""> 標(biāo)簽
- 使用 JSONP 解決跨域問題,有一種方法,前端以 <script> 同樣的方式發(fā)送請(qǐng)求,把返回的 JSON 數(shù)據(jù)封裝,然后以 JS 腳本形式返回
- JSONP 允許客戶端傳遞一個(gè) callback 參數(shù)請(qǐng)求跨域服務(wù)端,服務(wù)端返回?cái)?shù)據(jù)時(shí)用 callback 參數(shù)名作為返回的函數(shù)名來包裹住返回的 JSON 數(shù)據(jù)
**我們以 MOOC 網(wǎng)為例,來說明一下 JSONP **
當(dāng)我們?cè)L問 https://www.imooc.com/ 時(shí),會(huì)發(fā)送一個(gè) https://www.imooc.com/index/getstarlist AJAX 請(qǐng)求,下面是訪問后返回的 JSON 數(shù)據(jù)
我們以 JONP 的形式(https://www.imooc.com/index/getstarlist?callback=test )訪問
JSONP 的弊端?
- 需要在后端改動(dòng)代碼,比如在 Spring 后臺(tái)代碼中需要配置一個(gè) AbstractJsonpResponseBodyAdvice 切面,不過現(xiàn)在這個(gè)類已經(jīng)過時(shí)了,也就是說現(xiàn)在不推薦使用 JSONP 來解決跨域問題
- JSONP 默認(rèn)只支持 GET 方式的請(qǐng)求
- 發(fā)送的不是 XMLHttpRequest 請(qǐng)求(script),所以不支持異步事件等,不過這也是為什么 JSONP 可以解決跨域問題的原因
三、CORS 解決跨域問題
CORS 跨資源共享(Cross-origin resource sharing)是一種機(jī)制,它通過添加 HTTP 頭信息,解決 AJAX 跨域資源訪問問題。
CORS 請(qǐng)求可以分為兩類:簡(jiǎn)單請(qǐng)求與非簡(jiǎn)單請(qǐng)求,主要區(qū)別是非簡(jiǎn)單請(qǐng)求在進(jìn)行訪問之前,會(huì)發(fā)送一個(gè)預(yù)檢請(qǐng)求。“預(yù)檢”請(qǐng)求首先通過 OPTIONS 方法向另一域上的資源發(fā)送HTTP請(qǐng)求,以便確定實(shí)際請(qǐng)求是否安全發(fā)送。為了防止每次非簡(jiǎn)單請(qǐng)求之前都發(fā)送預(yù)檢請(qǐng)求,可以在服務(wù)端設(shè)置預(yù)檢請(qǐng)求的緩存的時(shí)間。
簡(jiǎn)單請(qǐng)求
- 請(qǐng)求方法為 HEAD、GET、POST 中的 1 種
- 請(qǐng)求的 header 中沒有自定義的請(qǐng)求頭
- Content-Type 為以下幾種:application/x-www-form-urlencoded、multipart/form-data、text/plain
非簡(jiǎn)單請(qǐng)求
- header 中包含自定義請(qǐng)求頭 的 AJAX 請(qǐng)求
- PUT、DELETE 形式的 AJAX 請(qǐng)求
- Content-Type 字段的類型是 application/json 等
我自己在本地寫了一個(gè)測(cè)試跨域的 demo(Spring Boot),通過端口 8082 發(fā)出請(qǐng)求(攜帶自定義的請(qǐng)求頭)訪問端口為 8081 的服務(wù)。下面是 Chrome 控制臺(tái)有關(guān) HTTP 的控制信息
通過上面的圖可以看出 CORS 解決跨域問題的關(guān)鍵所在,添加必要的請(qǐng)求頭與響應(yīng)頭信息。下面是有關(guān)的頭信息介紹
HTTP 響應(yīng)首部字段
- Access-Control-Allow-Origin:指定了允許訪問該資源的外域 URI。對(duì)于不需要攜帶身份憑證的請(qǐng)求,服務(wù)器可以指定該字段的值為通配符,表示允許來自所有域的請(qǐng)求。
- Access-Control-Allow-Methods:指明了實(shí)際請(qǐng)求所允許使用的 HTTP 方法
- Access-Control-Expose-Headers:在跨域訪問時(shí),XMLHttpRequest 對(duì)象的getResponseHeader() 方法只能拿到一些最基本的響應(yīng)頭,如果要攜帶自定義的請(qǐng)求頭,需要在該首部中進(jìn)行允許的請(qǐng)求頭放入白名單
- Access-Control-Max-Age:非簡(jiǎn)單請(qǐng)求預(yù)檢命令的最大緩存時(shí)間,在緩存時(shí)間內(nèi),對(duì)于非簡(jiǎn)單請(qǐng)求,不會(huì)再發(fā)送預(yù)檢請(qǐng)求
- Access-Control-Allow-Credentials:是否允許攜帶身份憑證(Cookie)的請(qǐng)求
HTTP 請(qǐng)求首部字段
- Origin:表明預(yù)檢請(qǐng)求或?qū)嶋H請(qǐng)求的源 URL
- Access-Control-Request-Method:用于預(yù)檢請(qǐng)求。其作用是,將實(shí)際請(qǐng)求所使用的 HTTP 方法告訴服務(wù)器
- Access-Control-Request-Headers:用于預(yù)檢請(qǐng)求。其作用是,將實(shí)際請(qǐng)求所攜帶的首部字段告訴服務(wù)器。
四、other
能解決跨域的方式還有很多,比如禁止瀏覽器的跨域、Nginx 解決跨域等。這里只講解了兩種常見的跨域方式,因?yàn)?JSONP 存在一些弊端,因此推薦使用 CORS 等方式來解決跨域問題。
跨域問題,涉及到很多有關(guān) HTTP 協(xié)議 的知識(shí),希望大家重視計(jì)算機(jī)基礎(chǔ)知識(shí)。上面那個(gè)測(cè)試的 demo 上傳到了 GitHub,demo 是用 Spring Boot 實(shí)現(xiàn)的,有需要的可以點(diǎn)我前往~
五、參考文獻(xiàn)
跨域資源共享 CORS 詳解l 阮一峰
【原創(chuàng)】說說JSON和JSONP,也許你會(huì)豁然開朗,含jQuery用例 隨它去吧
Cross-Origin Resource Sharing (CORS)
總結(jié)
- 上一篇: 招商银行ae蓝什么级别
- 下一篇: pos机怎么退款