48-【前后分离】跨域、CORS、JSONP


查看github源码

代码使用方法
  1. 安装 node-dev
    yarn global add node-dev

  2. 下载代码
    https://github.com/FrankFang/kuayu-1.git

  3. 进入 qq-com 运行 server.js
    cd kuayu-1/qq-com; node-dev server.js 8888

  4. 进入 frank-com 运行 server.js
    cd ../frank-com; node-dev server.js 9999

  5. 设置 hosts

     127.0.0.1 qq.com
     127.0.0.1 frank.com
    
  6. 打开两个页面 qq.com:8888/index.html 和 frank.com:9999/index.html

  7. 记得做完之后,删掉 hosts 里的两行,否则 qq.com 无法正常访问!

    taypVJ.md.png

同源策略

源:控制台得当前源,由协议+域名+端口号

window.origin
"https://www.baidu.com"
location.origin
"https://www.baidu.com"

同源:协议、域名、端口号完全一致,如"https://www.baidu.com"与"https://baidu.com"不同源

同源策略:为了保护用户隐私,不同源的页面之间,不准互相访问数据

浏览器规定:如果js运行在源A里,便只能访问源A里的数据,不允许跨域访问

举例子:js下载的源和js运行的源不同

frank.com/index中引用了cdn.com/1.js,则1.js是运行在frank中,源为frank.com,与下载的地方无关

举例子:无同源策略会如何?为什么要这设置?

当用户已登录时,可通过Ajax来获取用户列表,但是钓鱼网站也可以获取,由于无法区分发送者且后端不检查,虽referrer存在区别,所以浏览器加上同源策略来提高用户隐私安全性。

创建两个server

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6F6vwyki-1591253655019)(https://s1.ax1x.com/2020/06/03/tdTfeA.md.png)]

qq-com和frank-com

1.分别对两个加监听,用server.js,监听不同端口node server.js 9999和node server.js 8888

2.修改内容并实现自动监听:

新建终端1:yarn global add node-dev,再node-dev server.js 8888

新建终端2:node-dev server.js 8890

3.在qq.com中设置public中放首页index.html

fs.readFileSync(’./public/index.html’)

    if (path === "/index.html") {
        response.statusCode = 200;
        response.setHeader("Content-Type", "text/html;charset=utf-8");
        response.write(fs.readFileSync('./public/index.html'));
        response.end();
    }

4.加入qq.js和friends.json(双引号),设置好contentType

[{
    "name": "喻峰"
}, {
    "age": 18
}]

5.给frank设置public中加index.html和frank.js

//server.js部分代码
if (path === "/index.html") {
        response.statusCode = 200;
        response.setHeader("Content-Type", "text/html;charset=utf-8");
        response.write(fs.readFileSync('./public/index.html'));
        response.end();
    } else if (path === "/frank.js") {
        response.statusCode = 200;
        response.setHeader("Content-Type", "text/javascript;charset=utf-8");
        response.write(fs.readFileSync('./public/frank.js'));
        response.end();
    }
修改hosts

以管理员身份打开,所有文件

hosts位置:C:\Windows\System32\drivers\etc

设置本地域名映射

在etc内部后面加上

qq.com 127.0.0.1,便可以访问http://qq.com:8888/index.html

frank.com 127.0.0.1,便可以访问http://qq.com:8890/index.html

直接可qq.com:8888/index.html

tdxlX6.png

演示跨域被阻止 跨域AJAX

1.正常使用AJAX,可以访问/friend.json

  • ‘GET’, ‘./friends.json’
  • request.readyState === 4
  • request.status === 200
//index页面先引用qq.js
//qq.js代码实现ajax
const request = new XMLHttpRequest()
request.open('GET', './friends.json')
request.onreadystatechange = () => {
    if (request.readyState === 4 && request.status === 200) {
        console.log(request.response)
    }
}
request.send()

2.黑客偷数据,运行js不能访问,刷新黑客页面,终端也在增加请求

浏览器需要CORS,黑客请求发成功了,拿不到响应,跨域时浏览器不给他

知识点:路径的设置http://qq.com:8888/friends.json

const request = new XMLHttpRequest()
request.open('GET', 'http://qq.com:8888/friends.json')
request.onreadystatechange = () => {
    if (request.readyState === 4 && request.status === 200) {
        console.log(request.response)
    }
}
request.send()

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-j4buAvvQ-1591253655022)(https://s1.ax1x.com/2020/06/03/twAlPf.png)]

安全链条的强度取决于最弱一环,任何安全问题都要严格对待

1.为什么a.qq.com访问qq.com算跨域?

不同公司可能共用域名

2.为什么不同端口也算跨域?

不同公司共用服务器

3.为什么两公司ip一样,也算跨域?

ip可以公用

4.为什么可以跨域使用css、js和图片?

同源策略限制的是数据访问,由于只是引用,但是不清楚其内容,不可通过ajax跨域访问到

实现跨域
方法一:CORS

Cross-origin resource sharing

共享数据前,要对后台数据方的响应头,进行声明,允许某不同源网站访问

response.setHeader(‘Access-Control-Allow-Origin’, ‘http://frank.com:8890’)

//允许的网址为协议+域名+端口号完全相同
else if (path === "/friends.json") {
        response.statusCode = 200;
        response.setHeader('Access-Control-Allow-Origin', 'http://frank.com:8890')
        response.setHeader("Content-Type", "text/json;charset=utf-8");
        response.write(fs.readFileSync('./public/friends.json'));
        response.end();
    } 

允许多个网站访问: console.log(request.headers['referer'])

request.headers['referer']是对应http://frank.com:8890/index.html,把http://frank.com:8890放在响应头里

方法二:JSONP

兼容IE6\7\8\9,把数据写在JS文件中,在qq.com加入文件:server.js

//friends.js 关闭自动格式化
//变量版本friends.js 
window.xxx = {{data}}
//函数版本friends.js
window.xxx( {{data}} )

//server.js代码
else if (path === "/friends.js") {
        response.statusCode = 200;
        response.setHeader("Content-Type", "text/javascript;charset=utf-8");
        const string = fs.readFileSync("./public/friends.js").toString();
        const data = fs.readFileSync("./public/friends.json");
        const string2 = string.replace('{{data}}', data);
        response.write(string2);
        response.end();
    }

//引入其他源网页的js的数据:在frank.js中新建script标签,链接到qq.com下的friends.js,再将script标签加到body体中

//变量版本frank.js
const script=document.createElement('script')
script.src="http://qq.com:8888/friends.js"
script.onload=()=>{
    console.log(window.xxx)
} //下载成功,拿到数据
document.body.appendChild(script)

//函数版本frank.js
window.xxx=(data)=>{
    console.log(data)
}
const script=document.createElement('script')
script.src="http://qq.com:8888/friends.js"
document.body.appendChild(script)

关键点:

const string = fs.readFileSync("./public/friends.js").toString(); //获取{{data}}
const data = fs.readFileSync("./public/friends.json"); //获取JSON中的数据
const string2 = string.replace(’{{data}}’, data); //把json中数据替换到js中
在这里插入图片描述

此时查看控制台和window.xxx数据

twIhrj.png

总结JSONP思路

需求:frank.com访问qq.com中的朋友列表

实现:

  • 把qq.com的数据放在/friends.js,非真数据是占位
  • frank.com用script动态标签引用/friends.js
  • /friends.js执行,执行什么
  • 执行frank.com事先定义好的window.xxx函数,即回调函数
  • /friends.js执行window.xxx({{data}})
  • 然后通过frank.com就通过window.xxx获得数据
JSONP通过referer来指定网站访问

关键:判断referer的前三段是否一致

if(request.headers[‘referer’].indexOf(“http://frank.com:8890”)===0)

else if (path === "/friends.js") {        if(request.headers['referer'].indexOf("http://frank.com:8890")===0){
        response.statusCode = 200;
        response.setHeader("Content-Type", "text/javascript;charset=utf-8");
        const string = fs.readFileSync("./public/friends.js").toString();
        const data = fs.readFileSync("./public/friends.json");
        const string2 = string.replace('{{data}}', data);
        response.write(string2);
        response.end();
    }else{
        response.statusCode=404;
        response.end();
    }
    }
优化JSONP,用functionName

关键点:

  • 生成随机数:?functionName=${random}及都用下引号包住
  • 替换window函数的xxx:.replace('{{xxx}}',query.functionName);
  • 数字用引号包住 window[’{{xxx}}’]
//frank.js中
const random=Math.random()
window[random]=(data)=>{
    console.log(data)
}
const script=document.createElement('script')
script.src=`http://qq.com:8888/friends.js?functionName=${random}`
document.body.appendChild(script)

//qq.com中的server.js
 const string2=string.replace('{{data}}',data).replace('{{xxx}}',query.functionName);

//friends.js的代码
window['{{xxx}}']( {{data}} )

script标签创建、链接、执行、删除

script.onload=()=>{
    script.remove()
}
封装JSONP
//封装一下JSONP
function jsonp(url) {
    return new Promise((resolve, reject) => {
      const random = Math.random()
      window[random] = (data) => {
        resolve(data)
      };
      const script = document.createElement('script')
      script.src = `${url}?callback=${random}`
      script.onload = () => {
        script.remove()
      }
      script.onerror = () => {
        reject();
      }
      document.body.appendChild(script)
    })
  }

  jsonp("http://qq.com:8888/friends.js").then((data)=>{console.log(data)})

知识点:

  • functionName改成callback

  • friends.js是没有必要的 const string = fs.readFileSync("./public/friends.js").toString();改成const string =`window[’{{xxx}}’]({{data}})`

  • script.onerror = () => {reject();}的添加

JSONP是什么?

在跨域时,浏览器或者条件不支持CORS,我们必须以另一种方式实现跨域

在本网站创建个script标签,来请求其他网站的js文件,js文件会执行一个回调,回调里有我们需要的数据

命名:是生成随机数,再把这个名字以callback的参数传给后台,后台会将函数返给我们并执行

优点:兼容ie和实现跨域

缺点:由于是script标签引用

1.没有ajax那样能看待请求头和状态码

2.不能发送post请求

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值