资讯专栏INFORMATION COLUMN

跨域

MageekChiu / 1410人阅读

摘要:代码第日前瞻中国冲击金博尔特再战米羽球正直播柴飚洪炜出战男双力争会师决赛女排将死磕巴西郎平安排男陪练模仿对方核心执行结果用,不跨域的打开发送请求时,请求头内部没有当我用打开,出现跨域时。

一、同源策略

浏览器出于安全方面的考虑,只允许与本域下的接口交互(当前页面得url必须和接口得url是同源的)。不同源的客户端脚本在没有明确授权的情况下,不能读写对方的资源。

1、本域

同协议:如都是http或者https
同域名:如都是http://jirengu.com/a 和http://jirengu.com/b
同端口:如都是80端口
举个例子

http://jirengu.com/a/b.js 和 http://jirengu.com/index.php (同源)
不同源
http://jirengu.com/main.js 和 https://jirengu.com/a.php (协议不同)
http://jirengu.com/main.js 和 http://bbs.jirengu.com/a.php (域名不同,域名必须完全相同才可以)
http://jiengu.com/main.js 和 http://jirengu.com:8080/a.php (端口不同,第一个是80)
2、通过ajax获取数据,演示同源和不同源

首先打开hosts文件(window的地址是C:WindowsSystem32driversetchosts ),添加两条host记录


新建一个index.html文件,里面实现一个ajax获取数据的功能

hello world

新建一个js文件,里面实现一个静态路由功能的服务器

var http = require("http")
var fs = require("fs")
var path = require("path")
var url = require("url")

http.createServer(function(req, res){

  var pathObj = url.parse(req.url, true)

  switch (pathObj.pathname) {
    case "/getWeather":
      res.end(JSON.stringify({beijing: "sunny"}))
      break;

    default:
      fs.readFile(path.join(__dirname, pathObj.pathname), function(e, data){
        if(e){
          res.writeHead(404, "not found")
          res.end("

404 Not Found

") }else{ res.end(data) } }) } }).listen(8080)

gitbash cd到当前文件夹,通过node server.js打开服务器。
在浏览器输入localhost:8080,结果成功获取ajax数据

我把ajax请求地址改成http://a.com:8080/getWeather,结果报错了

我把浏览器的地址改为a.com 把ajax的地址改为b.com或者localhost,或者127.0.0.1都会出现跨域报错,即使他们的地址都是指向服务器。

二、JSONP(JSON with padding) 1、概念

HTML 中 script 标签可以加载其他域下的js,也就是说script的src能使用任何网站对应得文件,只要该网站愿意去提供这个东西。

这时候会向天气接口发送请求获取数据,获取数据后做为 js 来执行。 但这里有个问题, 数据是 JSON 格式的数据,直接作为 JS 运行的话我如何去得到这个数据来操作呢?

这样我们可以和后端商量一下,这样执行:


前端提前定义好showdata这个函数。当这个请求到达后端后,后端会去解析callback这个参数获取到字符串showData,在发送数据做如下处理:
之前后端返回数据: {"city": "hangzhou", "weather": "晴天"} 现在后端返回数据: showData({"city": "hangzhou", "weather": "晴天"}) 前端script标签在加载数据后会把 「showData({“city”: “hangzhou”, “weather”: “晴天”})」做为 js 来执行。实际上就是调用showData这个函数,同时参数是 {“city”: “hangzhou”, “weather”: “晴天”}。

总结:JSONP是通过 script 标签加载数据的方式去获取数据并把数据当做 JS 代码来执行。 提前在页面上声明一个函数,函数名通过接口传参的方式传给后台,后台解析到函数名后在原始数据上「包裹」这个函数名,发送给前端。换句话说,JSONP 需要对应接口的后端的配合才能实现。

2、举个栗子

2.1代码

var http = require("http")
var fs = require("fs")
var path = require("path")
var url = require("url")

http.createServer(function(req, res){
  var pathObj = url.parse(req.url, true)

  switch (pathObj.pathname) {
    case "/getNews":
      var news = [
        "第11日前瞻:中国冲击4金 博尔特再战200米羽球",
        "正直播柴飚/洪炜出战 男双力争会师决赛",
        "女排将死磕巴西!郎平安排男陪练模仿对方核心"
        ]
      res.setHeader("Content-Type","text/json; charset=utf-8")
      if(pathObj.query.callback){
        res.end(pathObj.query.callback + "(" + JSON.stringify(news) + ")")
      }else{
        res.end(JSON.stringify(news))
      }

      break;

    default:
      fs.readFile(path.join(__dirname, pathObj.pathname), function(e, data){
        if(e){
          res.writeHead(404, "not found")
          res.end("

404 Not Found

") }else{ res.end(data) } }) } }).listen(8080)



  

打开终端,cd到对应的文件夹,输入 node server.js ,浏览器打开 http://localhost:8080/index.html。

2.2执行结果

![clipboard.png](/img/bVbk

2.3分析

2.3.1

res.end(pathObj.query.callback + "(" + JSON.stringify(news) + ")")

数组和字符串相加,会把数组toString(),将数组转换为以‘,’分隔的字符串【1,2,3】=>"1,2,3"。如果我不用json.stringify传递的news就是一个字符串,html里面就无法当成数组使用

2.3.2

 if(pathObj.query.callback){
 res.end(pathObj.query.callback + "(" + JSON.stringify(news) + ")")

以下是pathobj的输出值,可以看到pathObj.query是一个对象,所以才可以使用pathObj.query.callback获取对应的值

2.3.3

 function appendHtml(news){
    console.log(news);  
    var html = "";
    for( var i=0; i";
    }
    console.log(html);
    $(".news").innerHTML = html;
  }

appendHtml函数收到的参数news是一个数组,和html参数是一个字符串

2.3.4

 script.src = "http://127.0.0.1:8080/getNews?callback=appendHtml";
    document.head.appendChild(script);
    document.head.removeChild(script);

把script放在document.head,是为了让这句代码执行发送请求。删除removechild,是为了美观,如果不删除,每次点击news都会重新产生一个script。如下图我点击news一次,head就会新增一个script

三、CORS

关于cors,我只是记录了一个简单的情况,经用于入门。详细可以看这篇文章跨域资源共享 CORS 详解

1、概念

CORS 全称是跨域资源共享(Cross-Origin Resource Sharing),是一种 ajax 跨域请求资源的方式,支持现代浏览器,IE支持10以上。

2、实现原理

当你使用 XMLHttpRequest 发送请求时,浏览器发现该请求不符合同源策略,会给该请求加一个请求头:Origin
后台进行一系列处理,如果确定接受请求则在返回结果中加入一个响应头:Access-Control-Allow-Origin(允许访问控制的域)和对应的值;
浏览器判断该相应头中是否包含 Origin 的值,如果有则浏览器会处理响应,我们就可以拿到响应数据,如果不包含浏览器直接驳回,这时我们无法拿到响应数据。

3、代码

server.js

var http = require("http")
var fs = require("fs")
var path = require("path")
var url = require("url")

http.createServer(function(req, res){
  var pathObj = url.parse(req.url, true)

  switch (pathObj.pathname) {
    case "/getNews":
      var news = [
        "第11日前瞻:中国冲击4金 博尔特再战200米羽球",
        "正直播柴飚/洪炜出战 男双力争会师决赛",
        "女排将死磕巴西!郎平安排男陪练模仿对方核心"
        ]

      res.setHeader("Access-Control-Allow-Origin","http://localhost:8080")
      //res.setHeader("Access-Control-Allow-Origin","*")
      res.end(JSON.stringify(news))
      break;
    default:
      fs.readFile(path.join(__dirname, pathObj.pathname), function(e, data){
        if(e){
          res.writeHead(404, "not found")
          res.end("

404 Not Found

") }else{ res.end(data) } }) } }).listen(8080)

index.html




  
4、执行结果

用http://127.0.0.1:8080/index.html,不跨域的打开index.html发送请求时,请求头内部没有origin

当我用http://localhost:8080打开index.html,出现跨域时。
请求头内部有Origin: http://localhost:8080,响应头有Access-Control-Allow-Origin: http://localhost:8080。两者相等,正常的获取数据

当我使用了a.com打开index.html时(我修改了host文件让a.com也指向127的本机服务器地址),出现了报错。因为服务器不允许a.com的网页使用资源

5、代码解析
res.setHeader("Access-Control-Allow-Origin","http://localhost:8080")
//res.setHeader("Access-Control-Allow-Origin","*")

这个表示服务器添加允许控制的域对应的地址,*表示允许所有接口用服务器的资源

四、降域 1、iframe和网页不同源

网页的内联iframe和网页不同源,我们不能通过js操作该iframe.比如我们在自己的网站上嵌套一个淘宝的frame,等用户先登陆了淘宝,然后登陆我们的网页的时候,处于frame的淘宝也是登陆状态,如果我能用js去操作这个用户的淘宝,那我就可以做很多坏事了。
2、举个例子



  



使用降域实现跨域

首先修改host文件,把a.com和b.com指向127.0.0.1,打开http-server。

用a.com网址打开a.html,其中b.jrg.com的iframe的地址是b.com,和网页不同源的。可以看到该frame可以正确加载,但我们不能用js操作它

用b.com地址打开a.html,其中b.jrg.com的iframe的地址是b.com,和网页同源。我们就可以用js去操作该iframe。

2、降域

如果当前页面和iframe域名后面部分一致都是jrg.com,我们可以使用document.domain = "jrg.com"降域的方式来实现跨域

五、postMessage

通过postMessage实现不同主域下frame的操作

window.frames[0].postMessage(this.value,"*");//* ,表示任何域下都可接受请求
 window.parent.postMessage(this.value, "*");



    
    
    
    Document


    


    






    
    
    
    Document





使用postMessage实现跨域

打开http-server,查看结果

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/99782.html

相关文章

  • ajax跨域,这应该是最全的解决方案了

    摘要:关于,强烈推荐阅读跨域资源共享详解阮一峰另外,这里也整理了一个实现原理图简化版如何判断是否是简单请求浏览器将请求分成两类简单请求和非简单请求。 前言 从刚接触前端开发起,跨域这个词就一直以很高的频率在身边重复出现,一直到现在,已经调试过N个跨域相关的问题了,16年时也整理过一篇相关文章,但是感觉还是差了点什么,于是现在重新梳理了一下。 个人见识有限,如有差错,请多多见谅,欢迎提出iss...

    ytwman 评论0 收藏0
  • 大话javascript 5期:跨域

    摘要:同源策略所谓同源是指协议,域名,端口均相同。同源策略是浏览器的一个安全功能,不同源的客户端脚本在没有明确授权的情况下,不能读写对方资源。需注意的是由于同源策略的限制,所读取的为跨域请求接口所在域的,而非当前页。 一、什么是跨域 1.URL解析 URL (Uniform Resource Locator )统一资源定位符(URL)是用于完整地描述Internet上网页和其他资源的地址的...

    jzzlee 评论0 收藏0
  • 用本地运行的demo快速入门跨域

    摘要:学习建议在学习其中一种跨域方法的时候,建议边运行项目里的,边在网上搜索博客文章学习这种跨域方法,这样有助于快速并且深入理解跨域。鉴于网上有很多文章详细讲述跨域知识,只是少了可以本地运行的,所以这里就不再赘述跨域知识。 前言 因为学习跨域需要配置本地服务器,可能会比较麻烦,所以自己根据网上的博客写了大多数跨域的简单demo,可以自己在本地运行,而且不用配置服务器。自己对于跨域的理解刚开始...

    yy736044583 评论0 收藏0
  • 用本地运行的demo快速入门跨域

    摘要:学习建议在学习其中一种跨域方法的时候,建议边运行项目里的,边在网上搜索博客文章学习这种跨域方法,这样有助于快速并且深入理解跨域。鉴于网上有很多文章详细讲述跨域知识,只是少了可以本地运行的,所以这里就不再赘述跨域知识。 前言 因为学习跨域需要配置本地服务器,可能会比较麻烦,所以自己根据网上的博客写了大多数跨域的简单demo,可以自己在本地运行,而且不用配置服务器。自己对于跨域的理解刚开始...

    GraphQuery 评论0 收藏0
  • 用本地运行的demo快速入门跨域

    摘要:学习建议在学习其中一种跨域方法的时候,建议边运行项目里的,边在网上搜索博客文章学习这种跨域方法,这样有助于快速并且深入理解跨域。鉴于网上有很多文章详细讲述跨域知识,只是少了可以本地运行的,所以这里就不再赘述跨域知识。 前言 因为学习跨域需要配置本地服务器,可能会比较麻烦,所以自己根据网上的博客写了大多数跨域的简单demo,可以自己在本地运行,而且不用配置服务器。自己对于跨域的理解刚开始...

    Integ 评论0 收藏0
  • javascript跨域

    摘要:实现跨域的原理通过方式请求载入并执行一个文件,相当于通过的形式的导入一个外部的方法语法该函数是简写的函数,等价于在中,您可以通过使用形式的回调函数来加载其他网域的数据,如。将自动替换为正确的函数名,以执行回调函数。 更多详情见http://blog.zhangbing.club/Ja... 最近在项目开发的过程中遇到一些Javascript 跨域请求的问题,今天抽空对其进行总结一下,以...

    PingCAP 评论0 收藏0

发表评论

0条评论

MageekChiu

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<