网上说了不少不少,可是看完以后仍是很混乱,因此我本身从新总结一下。
解决 js 跨域问题一共有8种方法,javascript
各个方法都有各自的优缺点,可是目前前端开发方面比较经常使用的是 jsonp,反向代理,CORS:html
CORS是跨源资源分享(Cross-Origin Resource Sharing)的缩写。它是W3C标准,是跨源AJAX请求的根本解决方法。优势是正统,符合标准,缺点是:前端
JSONP 优势是对旧式浏览器支持较好,缺点是:java
反向代理都可以兼容以上的肯定,可是仅仅做为前端开发模式的时候使用,在正式上线环境较少用到。node
这里主要说明这三种方式。其余方式暂不说明。
跨域问题通常只出如今前端开发中使用 javascript 进行网络请求的时候,浏览器为了安全访问网络请求的数据而进行的限制。jquery
提示的错误大体以下:ios
No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://XXXXXX' is therefore not allowed access.
由于浏览器收到同源策略的限制,当前域名的js只能读取同域下的窗口属性。git
同源指的是三个源头同时相同:github
举例来讲,http://www.example.com/dir/page.html
这个网址,web
协议是 http:// 域名是 www.example.com 端口是80 //它的同源状况以下: http://www.example.com/dir2/other.html:同源 http://example.com/dir/other.html:不一样源(域名不一样) http://v2.www.example.com/dir/other.html:不一样源(域名不一样) http://www.example.com:81/dir/other.html:不一样源(端口不一样)
同源策略限制了如下行为:
大概能够知道跨域其实就是同源策略致使的,而且知道同源策略的原理。
详细的同源策略相关,能够参考http://www.ruanyifeng.com/blog/2016/04/same-origin-policy.html
反向代理和正向代理的区别:
那么咱们能够理解为反向代理
如何使用反向代理服务器来达到跨域问题解决:
本地反向代理服务器接收到后:
如今前端开发通常使用 nodejs来作本地反向代理服务器
// 在 express 以后引入路由 var app = express(); var apiRoutes = express.Router(); app.use(bodyParser.urlencoded({extended:false})) // 自定义 api 路由 apiRoutes.get("/lyric", function (req, res) { var url = "https://c.y.qq.com/lyric/fcgi-bin/fcg_query_lyric_new.fcg"; axios.get(url, { headers: { // 修改 header referer: "https://c.y.qq.com/", host: "c.y.qq.com" }, params: req.query }).then((response) => { var ret = response.data if (typeof ret === "string") { var reg = /^\w+\(({[^()]+})\)$/; var matches = ret.match(reg); if (matches) { ret = JSON.parse(matches[1]) } } res.json(ret) }).catch((e) => { console.log(e) }) }); // 使用这个路由 app.use("/api", apiRoutes);
JSONP有些文章会叫动态建立script,由于他确实是动态写入 script 标签的内容从而达到跨域的效果:
<script>、<img>、<iframe>
)是不受该政策限制的,所以咱们能够经过向页面中动态添加<script>
标签来完成对跨域资源的访问,这也是 JSONP 方案最核心的原理,换句话理解,就是利用了【前端请求静态资源的时候不存在跨域问题】这个思路。实现 jsonp 的方式:
引用来自http://www.javashuo.com/article/p-ayiskmas-bm.html的图
ip.js
)callback=foo
的名字是一致的)jsonp 的方式
请求。ip.js
)到客户端客户端浏览器,解析script标签,并执行返回的javascript文件,此时数据做为参数,传入到了客户端预先定义好的 callback 函数里。
foo({XXXXX})
)这是一个实例 demo:
服务器端文件ip.js
foo({ "ip": "8.8.8.8" });
客户端文件 jsonp.html
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title></title> <script> // 动态插入 script 标签到 html 中 function addScriptTag(src) { var script = document.createElement('script'); script.setAttribute("type","text/javascript"); script.src = src; document.body.appendChild(script); } // 获取 jsonp 文件 window.onload = function () { addScriptTag('http://example.com/ip?callback=foo'); } // 执行本地的 js 逻辑,这个要跟获取到的 jsonp 文件的函数要一致 function foo(data) { console.log('Your public IP address is: ' + data.ip); }; </script> </head> <body> </body> </html>
CORS是一个W3C标准,全称是"跨域资源共享"(Cross-origin resource sharing)。它容许浏览器向跨源服务器,发出XMLHttpRequest
请求,从而克服了AJAX只能同源使用的限制。
所以,实现CORS通讯的关键是服务器端。只要服务器端实现了CORS接口,就能够跨源通讯。
只要同时知足如下两大条件,就属于简单请求。
(1) 请求方法是如下三种方法之一:
(2)HTTP的头信息不超出如下几种字段:
凡是不一样时知足上面两个条件,就属于非简单请求。
若是是简单请求的话,会自动在头信息之中,添加一个Origin字段
GET /cors HTTP/1.1 Origin: http://api.bob.com Host: api.alice.com Accept-Language: en-US Connection: keep-alive User-Agent: Mozilla/5.0...
这个Origin对应服务器端的Access-Control-Allow-Origin
设置,因此通常来讲须要在服务器端加上这个Access-Control-Allow-Origin 指定域名|*
若是是非简单请求的话,会在正式通讯以前,增长一次HTTP查询请求,称为"预检"请求(preflight)。
浏览器先询问服务器,当前网页所在的域名是否在服务器的许可名单之中,以及可使用哪些HTTP动词和头信息字段。只有获得确定答复,浏览器才会发出正式的XMLHttpRequest请求,不然就报错。
须要注意这里是会发送2次请求,第一次是预检请求,第二次才是真正的请求!
首先发出预检请求:
// 预检请求 OPTIONS /cors HTTP/1.1 Origin: http://api.bob.com Access-Control-Request-Method: PUT Access-Control-Request-Headers: X-Custom-Header Host: api.alice.com Accept-Language: en-US Connection: keep-alive User-Agent: Mozilla/5.0..
除了Origin字段,"预检"请求的头信息包括两个特殊字段。
(1)Access-Control-Request-Method
该字段是必须的,用来列出浏览器的CORS请求会用到哪些HTTP方法,上例是PUT。
(2)Access-Control-Request-Headers
该字段是一个逗号分隔的字符串,指定浏览器CORS请求会额外发送的头信息字段,上例是X-Custom-Header。
而后服务器收到"预检"请求之后:
检查了Origin
、Access-Control-Request-Method
和Access-Control-Request-Headers
字段之后,确认容许跨源请求,就能够作出回应。
// 预检请求的回应 HTTP/1.1 200 OK Date: Mon, 01 Dec 2008 01:15:39 GMT Server: Apache/2.0.61 (Unix) Access-Control-Allow-Origin: http://api.bob.com Access-Control-Allow-Methods: GET, POST, PUT Access-Control-Allow-Headers: X-Custom-Header Content-Type: text/html; charset=utf-8 Content-Encoding: gzip Content-Length: 0 Keep-Alive: timeout=2, max=100 Connection: Keep-Alive Content-Type: text/plain
最后一旦服务器经过了"预检"请求:
之后每次浏览器正常的CORS请求,就都跟简单请求同样,会有一个Origin头信息字段。服务器的回应,也都会有一个Access-Control-Allow-Origin头信息字段。
// 之后的请求,就像拿到了通行证以后,就不须要再作预检请求了。 PUT /cors HTTP/1.1 Origin: http://api.bob.com Host: api.alice.com X-Custom-Header: value Accept-Language: en-US Connection: keep-alive User-Agent: Mozilla/5.0...
详情参考这里http://www.ruanyifeng.com/blog/2016/04/cors.html
参考文档: