题目1: 什么是同源策略
同源策略限制从一个源加载的文档或脚本如何与来自另一个源的资源进行交互。这是一个用于隔离潜在恶意文件的关键的安全机制。
浏览器出于安全方面的考虑,只允许与本域下的接口交互。不同源的客户端脚本在没有明确授权的情况下,不能读写对方的资源。
所谓"同源"指的是"三个相同"。
- 协议相同
- 域名相同
- 端口相同
示例:
http://www.example.com/dir/page.html
这个网址,协议是http://
,域名是www.example.com
,端口是80(默认端口可以省略)。它的同源情况如下。
-
http://www.example.com/dir2/other.html
:同源 -
https://www.example.com/dir/other.html
:不同源(协议不同) -
http://example.com/dir/other.html
:不同源(域名不同) -
http://www.example.com:81/dir/other.html
:不同源(端口不同)
题目2: 什么是跨域?跨域有几种实现形式
跨域是指从一个域名的网页去请求另一个域名的资源。比如从http://www.baidu.com/
页面去请求https://www.zhihu.com
的资源。跨域的严格一点的定义是:只要 协议,域名,端口有任何一个的不同,就被当作是跨域。
有8种方法:
- JSONP
- CORS
- Server Proxy
- document.domain(降域)
- window.postMessage
- location.hash
- window.name
- WebSocket
若想了解详细情况,请仔细阅读这篇文章,很赞!!!
题目3: JSONP 的原理是什么
-
html中script标签可以引入其他域下的js,不受同源策略的限制比如引入线上的jquery库。利用这个特性,可实现跨域访问接口。需要后端支持
-
script标签:在页面中动态插入script,script标签的src属性就是后端api接口的地址;这样加载script标签脚本直接调用本地方法,而script标签会立即执行脚本,示例:
getNews?callback=appendHtml
-
后端:后端需要解析callback参数值,并将该值和返回数据拼接。示例:
res.send(req.query.callback + '(' + JSON.stringify(data) + ')')
前端:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<div class="container">
<ul class="news">
<li>233</li>
<li>323</li>
<li>332</li>
</ul>
<button class="change">换一组</button>
</div>
<script>
let $ = (className) => document.querySelector(className)
$('.change').addEventListener('click',function(){
var script = document.createElement('script')
script.src = 'http://localhost:8080/getNews?callback=appendHtml'
document.head.appendChild(script)
document.head.removeChild(script)
})
// appendHtml(["321","987","159"])
function appendHtml(news){
var html = ''
for(var i=0;i<news.length;i++){
html += '<li>' + news[i] + '</li>'
}
console.log(html)
$('.news').innerHTML = html
}
</script>
</body>
</html>
后端;
app.get('/getNews',function(req,res){
var news = [
'123',
'456',
'789',
'321',
'654',
'987',
'753',
'159',
'852'
]
var data = []
for(var i=0;i<3;i++){
var index = parseInt(Math.random() * news.length)
data.push(news[index])
news.splice(index,1)
}
var cb = req.query.callback
var show = cb + '(' + JSON.stringify(data) + ')'
console.log(show)
if(cb){
res.send(show)
}else{
res.send(data)
}
})
题目4: CORS是什么
CORS是一个W3C标准,全称是"跨域资源共享"(Cross-origin resource sharing)。它允许浏览器向跨源服务器,发出XMLHttpRequest请求,从而克服了AJAX只能同源使用的限制。
CORS 存在以下三种主要场景,分别是简单请求,预检请求和附带身份凭证的请求。
1.简单请求:若只使用 GET, HEAD 或者 POST 请求,且除 CORS 安全的首部字段集合外,无人为设置该集合之外的其他首部字段,同时 Content-Type 值属于下列之一,那么该请求则可以被视为简单请求:
application/x-www-form-urlencodedmultipart/form-datatext/plain
此情况下,若服务端返回的 Access-Control-Allow-Origin: *,则表明该资源可以被任意外域访问。若要指定仅允许来自某些域的访问,需要将*
设定为该域,例如:Access-Control-Allow-Origin: http://foo.example
2.预检请求:与前述简单请求不同,该要求必须首先使用 OPTIONS 方法发起一个预检请求到服务器,以获知服务器是否允许该实际请求。当请求满足以下三个条件任意之一时, 即应首先发送预检请求:
- 使用了 PUT, DELETE, CONNECT, OPTIONS, TRACE, PATCH 中任一的 HTTP 方法
- 人为设置了对 CORS 安全的首部字段集合之外的其他首部字段
- Content-Type 的值不属于下列之一
application/x-www-form-urlencodedmultipart/form-datatext/plain
预检请求完成之后(通过 OPTIONS 方法实现),才发送实际请求。一个示范 HTTP 请求如下所示:
var invocation = new XMLHttpRequest();
var url = 'http://bar.other/resources/post-here/';
var body = '<?xml version="1.0"?><person><name>Arun</name></person>';
function callOtherDomain(){
if(invocation)
{
invocation.open('POST', url, true);
invocation.setRequestHeader('X-PINGOTHER', 'pingpong');
invocation.setRequestHeader('Content-Type', 'application/xml');
invocation.onreadystatechange = handler;
invocation.send(body);
}
}
3.附带身份凭证的请求:这种方式的特点在于能够在跨域请求时向服务器发送凭证请求,例如 Cookies (withCredentials 标志设置为 true)。
一般而言,对于跨域 XMLHttpRequest 或 Fetch 请求,浏览器不会发送身份凭证信息。如果要发送凭证信息,需要设置 XMLHttpRequest 的某个特殊标志位。但是需要注意的是,如果服务器端的响应中未携带 Access-Control-Allow-Credentials: true
,浏览器将不会把响应内容返回给请求的发送者。
附带身份凭证的请求与通配符
对于附带身份凭证的请求,服务器不得设置 Access-Control-Allow-Origin 的值为*
。
这是因为请求的首部中携带了 Cookie 信息,如果 Access-Control-Allow-Origin 的值为*
,请求将会失败。而将 Access-Control-Allow-Origin 的值设置为 http://foo.example,则请求将成功执行。
另外,响应首部中也携带了 Set-Cookie 字段,尝试对 Cookie 进行修改。如果操作失败,将会抛出异常。
MDN 引例如下:
var invocation = new XMLHttpRequest();
var url = 'http://bar.other/resources/credentialed-content/';
function callOtherDomain(){
if(invocation) {
invocation.open('GET', url, true);
invocation.withCredentials = true;
invocation.onreadystatechange = handler;
invocation.send();
}
}
题目5: 根据视频里的讲解演示三种以上跨域的解决方式 ,写成博客
参考链接:
网友评论