什么是跨域:
浏览器处于安全方面的考虑,只允许与同源下的接口交互,也就是浏览器的
同源策略。
同源策略控制了从同一个源加载的文档或脚本如何与来自另一个源的资源进
行交互。这是一个用于隔离潜在恶意文件的重要安全机制。
同源指:协议、域名、端口号必须一致。
同源策略控制了不同源之间的交互,例如在使用XMLHttpRequest或标签时会受到同源策略的限制。这些交互通常分为以下三类:
- 通常允许跨域写操作(Croos-origin writes),列链接(links),重定向以及表单提交。特定少数的HTTP请求需要添加 preflight。
- 通常允许跨域资源嵌入(Cross-origin embedding)。
- 通常不允许跨域读操作(Cross-origin reads),但可以通过内嵌资源来巧妙的进行读取访问。列可以读取嵌入图片的高度和宽度,调用内嵌脚本的方法,或 availability of an embedded resource。
跨域的解决方法
jsonp
利用script标签不受跨域限制而形成的一种方案
原理:
- 同源策略只限制Ajax请求,不限制script标签加载js。可以通过script标签请求资源,并提前写好接收函数。
- 服务器收到请求后,从callback参数得到fn,把原始数据(假设是{a:1})处理后变成handleData({a:1})。
- script里的资源加载后会当成js执行相当于执行handleData({a:1}),即可在预定义的handleData函数里处理数据。
代码:服务器端:
const http = require('http');
const url = require('url');
http.createServer((req, res)=>{
let urlObj = url.parse(req.url, true);
if(urlObj.pathname === '/login'){
let data = {urldata:'This is login page'};
res.end(`${urlObj.query.callback}(${JSON.stringify(data)})`);
}else{
req.writeHead(404,'404 not found');
res.end('404 Not Found');
}
}).listen(2020)
console.log('监听 http://127.0.0.1:3030');
页面js:
<script>
function showData(data) {
console.log(data); //
}
</script>
<script src="http://127.0.0.1:3030/login?callback=showData"></script>
jsonp解决跨域的缺点:
只支持get请求,不支持post、put、delete等请求,
不安全,容易受[xss][18]攻击。
cors
跨域资源共享标准新增了一组 HTTP 首部字段,允许服务器声明哪些源站
有权限访问哪些资源。另外,规范要求,对那些可能对服务器数据产生副
作用的 HTTP 请求方法(特别是 GET 以外的 HTTP 请求,或者搭配某些
MIME 类型的 POST 请求),浏览器必须首先使用 OPTIONS 方法发起一
个预检请求(preflight request),从而获知服务端是否允许该跨域请
求。服务器确认允许之后,才发起实际的 HTTP 请求。在预检请求的返回
中,服务器端也可以通知客户端,是否需要携带身份凭证(包括 Cookies
和 HTTP 认证相关数据)。
原理:
- 发送Ajax请求时,浏览器发现该请求不符合同源策略,会给该请求加一个请求头:Origin。
后台收到请求后,如果确定接受请求则在返回结果中加一个响应头:Access-Control-Allow-Origin.
浏览器判断该响应头中是否包含当前Origin的值,如果有则浏览器会处理响应,我们就可以拿到响应数据,如果没有浏览器直接驳回。
代码:服务器端:
const http = require('http');
const url = require('url');
http.createServer((req, res)=>{
let urlObj = url.parse(req.url, true);
if(urlObj.pathname === '/getWeather'){
res.setHeader('Access-Control-Allow-Origin', 'https://www.baidu.com');
res.end(JSON.stringify( { city: 'hangzhou', weather: 'sunny' } ));
}else {
res.writeHead(404, 'Not Found');
res.end('not found');
}
}).listen(9090)
console.log('可以在 https://www.baidu.com 中访问getWeather接口了!');
fetch('http://127.0.0.1:9090/getWeather');
.then(res => res.json());
.then(data => console.log(data));
Nginx (engine x) 是一个高性能的HTTP和反向代理服务器,
也是一个IMAP/POP3/SMTP服务器
原理:
-
正向代理:代理位于网站和客户端中间,
客户端无法访问某网站,就将请求发送给代理服务器,代理从网站取回来再发送给客户端,网站并不知道为谁提供服务 -
反向代理:客户端访问某网站的一个页面,但是网站并没有,就偷偷从另外一台服务器上取回来,然后作为自己的内容吐给用户,用户不知道真正提供服务的是谁对于浏览器来说,访问的就是同源服务器上的一个url。而nginx通过检测url前缀,把http请求转发到后面真实的物理服务器。并通过rewrite命令把前缀再去掉。这样真实的服务器就可以正确处理请求,并且并不知道这个请求是来自代理服务器的。
简单说,nginx服务器欺骗了浏览器,让它认为这是同源调用,从而解决了浏览器的跨域问题。又通过重写url,欺骗了真实的服务器,让它以为这个http请求是直接来自与用户浏览器的。
代码:
// client.html
let xhr = new XMLHttpRequest;
xhr.open('get', 'http://localhost/a.json', true);
xhr.onreadystatechange = function() {
if(xhr.readyState === 4){
if(xhr.status >= 200 && xhr.status < 300 || xhr.status === 304 ){
console.log(xhr.response);
}
}
}
// server.js
let express = require('express');
let app = express();
app.use(express.static(__dirname));
app.listen(3000);
// nginx.conf
location / {// 代表输入/时默认去打开root目录下的html文件夹
root html;
index index.html index.htm;
}
location ~.*\.json{//代表输入任意.json后去打开json文件夹
root json;
add_header "Access-Control-Allow-Origin" "*";
}