b站视频链接
跨域&解决方案
浏览器的同源策略
同源策略概述
浏览器为确保资源安全,而遵循的一种策略
什么是源
- 源的组成部分源=协议+域名+端口号
- 下面表格中,只有最后一行的两个源是同源
- 同源请求与非同源请求
- 总结:【所处源】与【目标源】不一致,就是【非同源】,又称【异源】或【跨域】
跨域会受到哪些限制
备注:在上述限制中,浏览器限制a ja x获取数据的限制是影响最的的一个,且实际开发中经常遇到
限制DOM访问
<body>
<button onclick="showDOM()">showDOM</button>
<!-- <iframe id="framePage" src="./demo.html" frameborder="0"></iframe> -->
<iframe id="framePage" src="https://www.baidu.com"></iframe>
</body>
<script type="text/javascript">
function showDOM() {
const framePage = document.getElementById('framePage')
console.log(framePage.contentWindow.document) //同源的可以获取,非同源的无法获取
}
</script>
限制Cookie访问
<body>
<button onclick="showCookie()">showCookie</button>
<iframe id="framePage" src="https://www.baidu.com"></iframe>
</body>
<script type="text/javascript">
function showCookie() {
console.log(document.cookie)
const framePage = document.getElementById('framePage')
console.log(framePage.contentWindow.document.cookie)
}
</script>
限制Ajax获取数据
<body>
<button onclick="getData()">getData</button>
</body>
<script type="text/javascript">
async function getData() {
const url = 'https://www.toutiao.com/hot-event/hot-board/?origin=toutiao_pc'
let result = await fetch(url)
let data = await result.json()
console.log(data)
}
</script>
Access to fetch at 'https://www.toutiao.com/hot-event/hot-board/?origin=toutiao_pc' from origin 'http://127.0.0.1:5500' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
几个注意点
- 跨域限制仅存在浏览器端,服务端不存在跨域限制
- 即使跨域了,ajax请求也可以正常发出,但相应数据不会交给开发者
link标签
、script标签
、img标签
等这些标签发出的请求也可能跨域,只不过浏览器对标签跨域不做严格限制,对开发几乎无影响
CORS解决Ajax跨域方案
CORS概述
CORS全称:
Cross-Origin Rresource Sharing(跨域资源共享)
,是用于控制浏览器校验跨域请求的一套规范,服务器依照CORS规范,添加特定响应头来控制浏览器校验,大致规则如下:
- 服务器明确表示拒绝跨域请求,或没有表示,则浏览器校验不通过
- 服务器明确表示允许跨域请求,则浏览器校验通过
备注:使用CORS解决跨域是最正统的方式,且要求服务器是“自己人”
CORS解决简单请求跨域
整体思路:服务器在给出响应时,通过添加
Access-Control-Allow-Origin
响应头,来明确表达允许某个源发起跨域请求,随后浏览器在校验时,直接通过
请求代码
<body>
<button onclick="getData()">getData</button>
</body>
<script type="text/javascript">
async function getData() {
const url = 'http://127.0.0.1:8081/students'
let result = await fetch(url)
let data = await result.json()
console.log(data)
}
</script>
服务器代码(以express框架为例)
const express = require('express')
const app = express()
const students = [
{
id: 1,
name: 'st1'
},
{
id: 2,
name: 'st2'
},
{
id: 3,
name: 'st3'
}
]
app.get('/students', (req, res) => {
res.setHeader('Access-Control-Allow-Origin', 'http://127.0.0.1:5500')
res.send(students)
})
// 启动服务器
app.listen('8081', () => {
console.log(`Server is running at http://127.0.0.1:8081`)
})
简单请求与复杂请求
CORS会把请求分为两类,分别是 简单请求、复杂请求
CORS解决复杂请求跨域
- 第一步:服务器先通过浏览器的预检请求,服务器需要返回如下响应头
- 第二步:处理实际的跨域请求(与处理简单请求跨域的方式相同)请求代码:
<body> <button onclick="getData()">getData</button></body><script type="text/javascript"> async function getData() { const url = 'http://127.0.0.1:8081/students' let result = await fetch(url, { method: 'GET', headers: { name: 'ym', age: 120 } }) let data = await result.json() console.log(data) }</script>
服务端代码:const express = require('express')const app = express()const students = [ { id: 1, name: 'st1' }, { id: 2, name: 'st2' }, { id: 3, name: 'st3' }]app.options('/students', (req, res) => { res.setHeader('Access-Control-Allow-Origin', 'http://127.0.0.1:5500') res.setHeader('Access-Control-Allow-Method', 'GET') res.setHeader('Access-Control-Allow-Headers', 'name,age') res.setHeader('Access-Control-Max-Age', 7200) res.send()})app.get('/students', (req, res) => { res.setHeader('Access-Control-Allow-Origin', 'http://127.0.0.1:5500') res.send(students)})// 启动服务器app.listen('8081', () => { console.log(`Server is running at http://127.0.0.1:8081`)})
借助cors库快速完成配置
上述的配置需要自己配置响应头,或者需要自己手动封装中间件,借助cors库,可以更方便完成配置
- 安装cors
npm i cors
- 简单配置cors
app.use(cors())
- 完整配置cors
const corOptions = { origin: 'http://127.0.0.1:5500', //允许的源 methods: ['get', 'post', 'put', 'delete', 'head', 'options'], //允许的方法 allowHeaders: ['name', 'age'], //允许的自定义头 exposedHeaders: ['age'], //要暴露的响应头 optionsSuccessStatus: 200 //预检请求成功的状态码}app.use(cors(corOptions))
JSONP解决跨域问题
- JSONP概述:JSONP是利用script标签可以跨域加载脚本,且不受严格限制的特性,可以说是程序员智慧的结晶,早期一些浏览器不支持CORS的时候,可以靠JSONP解决跨域
- 基本流程1. 客户端创建一个script标签,并将其src属性设置为包含跨域请求的url。同时准备一个回调函数,这个回调函数用于处理返回的数据2. 服务端接收到请求后,将数据封装在回调函数中并返回3. 客户端的回调函数被调用,数据以参数的形式传入回调函数
- 图示
- 代码示例
<body> <button onclick="getData()">getData</button></body><script type="text/javascript"> function test(data) { console.log(data) } function getData() { const script = document.createElement('script') script.src = 'http://127.0.0.1:8081/students?callback=test' document.body.appendChild(script) script.onload = () => { script.remove() } }</script>``````app.get('/students', (req, res) => { const { callback } = req.query res.send(`${callback}(${JSON.stringify(students)})`)})
- jQuery封装的jsonp
<script src="http://libs.baidu.com/jquery/2.0.0/jquery.min.js"></script><script type="text/javascript"> $.getJSON('http://127.0.0.1:8081/students?callback=?', data => { console.log(data) })</script>
配置代理解决跨域
自己配置代理服务器
借助
http-proxy-middleware
使用ngin x搭建代理服务器
借助脚手架搭建服务器
版权归原作者 小小小的学习日记 所有, 如有侵权,请联系我们删除。