什么是同源?什么是跨域?
客户端向服务器发送请求的时候,如果协议,域名(IP)和端口都一样,则称为同源,但凡有一个不一样则跨域,跨域请求默认受到浏览器的安全策略的限制,浏览器会给出相应的错误信息,对于客户端而言意味着请求失败
-
同源和跨域是浏览器的行为--浏览器安全机制
-
请求要么同源要么跨域:不同源则跨域
-
所谓同源就是指请求的源和对应的响应服务器:协议一致,IP(域名)一致,端口一致
-
影响范围
ajax 请求数据会受到影响,但是 html 代码中,二次请求文件,比如图片 img src, 或者 script src 这些不会受到限制
客户端跨域
-
我想通过远程接口获取天气信息
-
找到接口:http://api.map.baidu.com/telematics/v3/weather?location=北京&output=json&ak=E4805d16520de693a3fe707cdc962045
-
发送请求,获取到天气数据
$.ajax({ type: 'get', url: 'http://api.map.baidu.com/telematics/v3/weather', data: { ak: 'zVo5SStav7IUiVON0kuCogecm87lonOj', location: '广州', output: 'json' }, success: function (result) { console.log(result.results[0].weather_data) } })
-
跨域错误信息
-
错误信息说明: 通过异步方式,从源http://127.0.0.1:5500向http://api.baidu...发送请求被CORS策略阻止了,不允许进行跨域请求
解决跨域
1.第一种 在服务器设置 ( Access-Control-Allow-Origin: *)(常用)
- CROS 数据服务器添加响应头 Access-Control-Allow-Origin: *
- 星号表示所有域名,也可用指定域名代替星号
2.第二种 Proxy 代理 (常用)
Proxy 代理,网页服务器,同时负责转发不同服务器的数据
只从网页服务器请求数据,那么网页和数据来自同一服务器,就不是跨域了
开发服务器转发代理配置步骤:
配置 vue.config.js
-
如何分辨哪些是数据请求?
proxy 是一个对象
对象里面是键值对, 其中 key 是用来匹配数据请求的
我们希望所有数据请求都能统一处理,无需重复声明
-
在所有数据请求的前面添加 /api 标识
-
然后就可以被 '/api' 拦截
-
-
将请求转向真实数据服务器
target 配置
代理解决跨域的根本在于服务器之间通讯受跨域影响, 可以用跟页面同域的服务器作为中转转发, 避免跨域问题.
3.第一种jsonp解决方式(但是在现在的前端领域并不常见了)
-
jsonp 利用 script 标签不受跨域限制的特性,使用 script 标签向数据服务器请求一个 js文件,数据服务器会将数据动态生成一个 js 文件响应
-
在ajax中实现跨域请求
在客户端实现跨域请求就称为
客户端跨域
ajax中通过设置dataType为jsonp就可以实现客户端跨域
// 关键代码:第11行 $.ajax({ type: 'get', url: 'http://api.map.baidu.com/telematics/v3/weather', data: { ak: 'zVo5SStav7IUiVON0kuCogecm87lonOj', location: '广州', output: 'json' }, // 开户跨域请求 dataType: 'jsonp', success: function (result) { console.log(result.results[0].weather_data) } })
jsonp客户端跨域的原理
1.客户端跨域的本质是利用了script标签的src属性的天然跨域特性来实现
2.客户端发送请求的时候,传递一个客户端存在的函数名称到服务器,如<script src='http://127.0.0.1:3000/getData?callback=fn' ></script>
3.服务器中获取数据,根据接收的函数名称拼接成函数调用形式,如 res.end('fn({ "a": 1, "b" : 2 })')
4.通过script发送的请求,返回值默认会以js语法进行解析,客户端接收从服务器返回的数据(如:fn({ "aa": 11, "bb" : 22 })),以js语法解析,恰巧客户端有一个fn函数,完美
5.客户端获取到数据
客户端
<script>
function fun(data){
console.log("data:",data)
}
</script>
// 发送请求,传入客户端定义好的函数
<script src="http://127.0.0.1:3000/getUserList?callback=fun"></script>
服务器端
// 1.引入http模块
const http = require('http')
// 读取文件需要fs模块
const fs = require('fs')
// 2.创建服务器
const server = http.createServer()
// 3.添加服务器的端口监听
server.listen(3000, function () {
console.log('服务器开好了: http://127.0.0.1:3000')
})
server.on('request', function (req, res) {
let url = req.url
let fun = req.url.split('=')[1]
console.log(fun)
let data = [{id:1,name:'jack'},{id:2,name:rose},{id:3,name:'tom'}]
if (url.indexOf('/getUserList?') === 0) {
fs.readFile(__dirname + "/data/users.json",'utf-8', function (err, data) {
if (err) {
res.end(`${fun}("404")`)
} else {
// 关键代码:服务器获取数据后,拼接数据和函数名称,返回函数的调用形式
res.end(`${fun}(${data})`)
}
})
}else{
res.end(`${fun}("404")`)
}
})
结果
总结:
所谓jsonp跨域就是利用了script标签的src属性的天然跨域特性,
在发送请求的时候,传递一个客户端的函数名称到服务器端,
服务器端获取数据,根据接收的函数名称拼接为函数调用的形式,
并返回到客户端,客户端获取返回数据的之后,按js语法进行解析,客户端就顺利的获取到数据了
只能发起get请求
可以理解的是,jsonp跨域严重的需要服务器端的配合,在现在的前端领域并不常见了