常见前端面试题--跨域

跨域相关问题 是最常见的基础面试题之一
出现原因:由于同源策略限制,同源策略是浏览器最核心也是最基本的安全功能,Web是构建在同源策略基础之上的。同源策略会阻止一个域的JS脚本和另一个域的内容进行交互。同源(指在同一个域)就是两个页面具有相同的协议(protocol)、主机(host)和端口号(port)。
什么是跨域:当一个请求的url的协议、域名、端口三者之间任意一个与当前页面url不同即为跨域
非同源限制
(1)无法读取非同源网页的Cookie、LocalStorage和IndexedDB
(2)无法接触非同源网页的DOM
(3)无法向非同源地址发送AJAX请求
跨域解决方法
(1)设置document.domain解决无法读取非同源的Cookie问题
浏览器通过document.domain属性来检查两个页面是否同源,因此将两个页面设置相同的document.domain,就可以共享Cookie(仅限主域相同,子域不同的跨域应用场景)
(2)跨文档通信API:window.postMessage()
调用postMessage方法实现父窗口 http://test1.com向子窗口http://test2.com发消息(子窗口同样可以使用该方法发送消息给父窗口)
主要使用于以下场景:

  • 页面和其打开的新窗口的数据传递
  • 多窗口之间消息的传递
  • 页面与嵌套的iframe消息传递
  • 上面三个场景的跨域数据传递
// 父窗口打开一个子窗口
var openWindow = window.open('http://test2.com', 'text');
// 父窗口向子窗口发消息(第一个参数代表发送的内容,第二个参数代表接收消息窗口的url)
openWindow.postMessage('Hello World!', 'http://test2.com');

调用message事件,监听对方发送的消息

window.addEventListener('message', function(e) {
  console.log(e.source);  // e.source 发送消息的窗口
  console.log(e.origin);  // e.origin 消息发向的网址
  console.log(e.data);  // e.data 发送的消息
}, false);

(3)JSONP
JSONP是服务器与客户端跨源通信的常用方法。最大特点就是简单实用,兼容性好(兼容低版本IE),缺点是只支持get请求,不支持post请求
网页通过添加一个

// 原生实现
<script src="http://test.com/data.php?callback=doSomeThing"></script>

// 向服务器test.com发起请求,该请求的查询字符串有一个callback参数,用来指定回调函数的名字
// 处理服务器返回回调函数的数据
<script tyoe="text/javascript">
  function doSomeThing(res) {
    // 处理获得的数据
    console.log(res.data);
  }
</script>

// jQuery ajax
$.ajax({
  url: 'http://www.test.com:8080/login',
  type: 'get',
  dataType: 'jsonp',  // 请求方式为jsonp
  jsonCallback: 'handleCallback',  // 自定义回调函数名
  data: {}
})

// Vue.js
this.$http.jsonp('http://www.domain2.com:8080/login', {
  params: {},
  jsonp: 'handleCallback',
}).then((res) => {
  console.log(res);
});

(4)CORS
CORS是跨域资源分享(Cross-Origin Resource Sharing)的缩写。是W3C标准,属于跨源AJAX请求的根本解决方法。
(分为两种方式,是否携带cookie决定)
-== 普通跨域请求:只需要服务器设置Access-Control-Allow-Origin==
-== 带cookie跨域请求,前后端都需要进行设置==
前端设置,根据 xhr.withCredentials字段判断是否带有cookie

// 原生ajax
var xhr = new XMLHttpRequest();  // IE8/9需要用window.XDomainRequest做兼容

// 假设固定前端携带cookie发起请求
xhr.withCredentials = true;

xhr.open('post', 'http://www.music.com:8080/login', true);
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlopended');
xhr.send('user=admin');

xhr.onreadystatechange = function() {
  if (xhr.readyState === 4 && xhr.status == 200) {
    alert(xhr.responseText);
  };
};

//  jQuery ajax
$.ajax({
  url: 'http://www.music.com:8080/login',
  type: 'get',
  data: {},
  xhrFields: {
    withCredentials: true  // 前端设置是否带cookie
  },
  crossDomain: true  // 会让请求头中包含跨域的额外信息,但不会含cookie
})

// vue-resource
Vue.http.options.credentials = true;
 
// axios
axios.defaults.withCredentials = true 

(5)服务器设置
服务器端对于CORS的支持,主要是通过设置Access-Control-Allow-Origin来进行的。如果浏览器检测到相应的设置,就可以允许Ajax进行跨域的访问。

  • Java后台设置
// 允许跨域访问的域名,若有端口需要写全(协议+域名+端口),若没有端口末尾不用加'/'
response.setHeader("Access-Control-Allow-Origin", "http://www.music.com");

// 允许前端带认证cookie:启用此项后,上面的域名不能为'*',必须指定具体的域名,否则浏览器会发出提示
response.setHeader("Access-Control-Allow-Credentials", "true");
// 提示OPTIONS检验时,后端需要设置两个常用的自定义头
response.setHeader("Access-Control-Allow-Headers", "Content-Type, X-Rquested-with");
  • Node.js后台
var http = request('http');
var serve = http.createServer();
var qs = require('querystring');  // Node.js内置模块querystring

server.on('request', function(req, res) {
  var postData = '';
  
  // 数据块接受中
  req.addLisener('data', function(chunk) {
    postData += chunk;
  })
  
  // 数据接收完毕
  req.addListener('end', function() {
    postData = qs.parse(postData);  // 将postData转为对象
    // querystring.parse()方法返回的对象不是原型,会继承自JavaScript的Object。意味着典型的Object方法如obj.toString()、obj.hasOwnProperty()等没有被定义并且不起作用。解决方法是:先将对象进行JSON字符串转化(JSON.stringify()),然后再转化成对象(JSON.parse())
    
    // 数据后台设置
    res.writeHead(200, {
      'Access-Control-Allow-Credentials': 'true',  // 后端允许发送Cookie
      'Access-Control-Allow-Origin': 'http://www.music.com',  // 允许访问的域(协议+域名+端口)
      'Set-Cookie': 'l=a123456;Path=/;Music=www.music.com;HttpOnly'  // HttpOnly属性,无法通过js脚本获取cookie信息,XSS攻击中无法通过document对象直接获取cookie
    });

    res.write(JSON.stringify(postData));
    res.end();
  });
});

server.listen('8080');
console.log('Server is runing!');
  • PHP后台(网上寻找)

(6)webpack本地代理
在webpack.config.js中利用WebpackDevServer配置本地代理,详情配置查看官方文档

https://webpack.docschina.org/configuration/dev-server/#root

(7)WebSocket
WebSocket是一种双向通信协议,实现浏览器与服务器的全双工通信,同时也是跨域的解决方案,在建立连接(需要借助HTTP协议)之后,WebSocket的服务器与客户端都能主动向对方发送或者接受数据,连接建立好了之后client和server之间的双向通信就与HTTP无关了
(8)Nginx反向代理
最简单的跨域的方式,实现原理类似与Node中间件代理,需要搭建一个中转Nginx服务器,用于转发请求。
只需配置nginx,并在相应文件中配置端口号

你可能感兴趣的:(前端面试常见问题,node.js,javascript)