浏览器跨域问题
1、什么是浏览器同源策略?
同源策略是一个重要的安全策略,它用于限制一个 origin
的文档或者它加载的脚本如何能与另一个源的资源进行交互,它能帮助阻隔恶意文档,减少可能被攻击的媒介。
所谓同源策略,是指只有在地址的:
- 协议名
- 域名
- 端口名
均一样的情况下,才允许访问相同的 cookie
、localStorage
,以及访问页面的 DOM
或是发送 Ajax
请求。
2、没有同源策略限制有哪些危险场景?
ajxa
请求Dom
的查询 同源策略确实能规避一些危险,不是说有了同源策略就安全,只是说同源策略是一种浏览器最基本的安全机制,毕竟能提高一点攻击的成本。
3、为什么浏览器会禁止跨域?
- 跨域只存在浏览器端,因为浏览器的形态很开放,需要对它进行限制。
- 同源策略用于保护用户信息安全,防止恶意窃取数据(
ajax
同源策略、Dom
同源策略)。
4、跨域有哪些解决方式?
jsonp
cors
postMessage
websocket
Node
中间件代理(两次跨域)nginx
反向代理window.name + iframe
location.hash + iframe
document.domain + iframe
5、CORS
常用的配置有哪些?
Access-Control-Allow-Origin
允许的域名Access-Control-Allow-Methods
允许的http
请求方法Access-Control-Allow-Headers
支持的请求头Access-Control-Allow-Credentials
是否发送cookie
Access-Control-Max-Age
以秒为单位的缓存时间
6、CORS
跨域的判定流程
- 浏览器先判断是否同源,若同源,直接发送数据,否则,发送跨域请求;
- 服务器收到跨域请求后,根据自身配置返回对应的文件头;
- 浏览器根据收到的响应头里的
Access-Control-Allow-origin
字段进行匹配,若无该字段说明不允许跨域,报错,有该字段进行比对,判断是否可以跨域。
7、什么是简单请求?
简单请求是指满足以下条件的:
- 使用
get
、post
、head
其中一种方法进行请求的; http
的头信息不超出一下情况:Accept
Accept-Language
Content-Language
Last-Event-ID
Content-Type
:值仅限于application/x-www-form-urlencoded
、multipart/form-data
、text/plain
- 请求中
XMLHttpRequestUpload
对象没有注册任何的事件监听器; XMLHttpRequestUpload
对象可以使用XMLHttpRequest.upload
属性访问。 请求中没有使用ReadableStream
对象。
8、非简单请求
对服务器有特殊要求的请求(简单请求之外就是非简单请求)。
例如:请求方式是 put
、delete
,Content-Type
的类型是 application/json
。
非简单请求会在正式通信前使用 options
发起一个预检请求,询问服务器当前的域名是否在服务器允许的名单之中,以及使用哪些头信息字段等。
9、有哪些方法可一嵌入跨源的资源?
script
标签,嵌入跨域脚本;link
标签,嵌入css
;img
标签,嵌入图片;video/audio
标签,嵌入视频、音频;object/embed/applet
标签,嵌入svg
/图片 等;svg
标签,嵌入svg
;- 通过
@font-face
嵌入字体; - 通过
iframe
嵌入资源
10、手动实现一个 JSONP
//Promise封装
function jsonp({ url, params, callback }) {
return new Promise((resolve, reject) => {
// 创建 script 标签
let script = document.createElement('script')
// 把 callback 挂载在 window 上,执行之后删除 script
window[callback] = function(data) {
resolve(data)
document.body.removeChild(script)
}
// 添加参数
params = { ...params, callback } // wd=b&callback=callFun
let arrs = []
for (let key in params) {
arrs.push(`${key}=${params[key]}`)
}
// 设置 script 的 URL
script.src = `${url}?${arrs.join('&')}`
// 插入 body 中
document.body.appendChild(script)
})
}
// 调用示例
jsonp({
url: 'http://localhost:3000/code',
params: { wd: 'hello world' },
callback: 'callFun'
}).then(data => {
console.log(data) // 你好啊
//再此回调结束后删除该script
})