目录
跨域定义
首页 web前端 H5教程 你值得了解的WEB前端跨域解决方案(代码详解)

你值得了解的WEB前端跨域解决方案(代码详解)

Sep 06, 2021 am 10:12 AM
web 前端

之前的文章《浅析Node中zip压缩和zip解压缩(附代码)》中,给大家介绍了Node中zip压缩和zip解压缩命令的使用详解。下面本篇文章给大家了解WEB前端跨域解决方案,伙伴们来看看吧。

你值得了解的WEB前端跨域解决方案(代码详解)

WEB前端跨域解决方案

跨域定义

广义的定义:跨域是指一个域下的文档或脚本试图去请求另一个域下的资源。

1、资源跳转: 链接、重定向、表单提交

2、资源嵌入:<link><script><img/><frame>dom标签,还有样式中background:url()@font-face()等文件外链

3、脚本请求:js发起的ajax请求、domjs对象的跨域操作等

同源策略

同源策略/SOP(Same origin policy)是一种约定,由Netscape公司 1995 年引入浏览器,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,浏览器很容易受到XSSCSFR等攻击。所谓同源是指“协议+域名+端口”三者相同,即便两个不同的域名指向同一个ip地址,也非同源。

同源策略限制以下几种行为:

1、CookieLocalStorageIndexDB无法读取

2、DOMJs对象无法获得

3、AJAX请求不能发送

跨域解决方案

1)jsonp跨域

关于jsonp的原理把握一下几点: 

1、html标签的src属性没有同源限制(支持跨域),浏览器解析script标签时,会自动下载src属性值(url)指向的资源;

2、script标签指向的资源文件被下载后,其中的内容会被立即执行;

3、服务器端的程序会解析src属性值中的url传递的参数,根据这些参数针对性返回一个/多个函数调用表达式,这些函数调用表达式的参数就是客户端跨域想得到的数据;

4、服务器生成、返回的文件中,表达式调用的函数是已经在本地提前定义好的,而参数就是希望从跨域服务器拿到的数据。字面的script标签可以,动态添加到dom树中的script也可以,后者更方便绑定事件。

5、只能实现get,也是他的弱点

实现:

// 服务端返回:
test({
  code: 0,
  message: "成功",
});
登录后复制
<!-- 原生js -->
<script>
  var script = document.createElement("script");
  script.type = "text/javascript";
  // 传参并指定回调执行函数为callback
  script.src = "http://www.chuchur.com/login?callback=test";
  document.head.appendChild(script);
  // 回调执行函数
  function test(res) {
    console.log(JSON.stringify(res));
  }
</script>
登录后复制
//jquery ajax:
$.ajax({
  url: "http://www.chuchur.com/login",
  type: "get",
  dataType: "jsonp", // 请求方式为jsonp
  jsonpCallback: "test", // 自定义回调函数名
  data: {},
});

//vue.js
this.$http
  .jsonp("http://www.chuchur.com/login", {
    params: {},
    jsonp: "test",
  })
  .then((res) => {
    console.log(res);
  });
登录后复制

2)document.domain + iframe 跨域

原理:这种方案只限于主域相同,子域不同的情况,其原理就是 两个页面通过js强制设置window.domain为主域,这样就实现了同域。

实现:

<!-- 父窗口 https://www.chuchur.com/a.html -->
<iframe id="iframe" src="https://b.chuchur.com/b.html"></iframe>
<script>
  document.domain = "chuchur.com";
  var user = "chuchur";
</script>
<!-- 子窗口 https://b.chuchur.com/b.html -->
<script>
  document.domain = "chuchur.com";
  // 获取父窗口中变量
  alert("从父窗口取得数据" + window.parent.user);
</script>
登录后复制

3)location.hash + iframe跨域

原理: 其原理就是通过URL传值,然后监听其hash值的变化,然后通过中间层做跳板,再利用父子窗口js parent最终来访问同域所有页面对象。

1: a.html ,域 2:b.html ,域 1:c.html

a.htmlb.html 不同域只能通过hash传值通讯。

b.htmlc.html 也不同域也只能单项通讯

a.htmlc.html 同域,所以c.html可以通过parent来访问a.html页面对象

实现

1、a.html:(www.chuchur.com/a.html)

<iframe
  id="iframe"
  src="http://www.chuchur.org/b.html"
  style="display:none; "
></iframe>
<script>
  var iframe = document.getElementById("iframe");
  // 向b.html传hash值
  setTimeout(function () {
    iframe.src = iframe.src + "#nick=chuchur";
  }, 1000);
  // 开放给同域c.html的回调方法
  function test(res) {
    alert("数据来自c.html ---> " + res);
  }
</script>
`
登录后复制

2、b.html:(www.chuchur.org/b.html)

<iframe
  id="iframe"
  src="http://www.chuchur.com/c.html"
  style="display:none; "
></iframe>
<script>
  var iframe = document.getElementById("iframe");
  // 监听a.html传来的hash值,再传给c.html
  window.onhashchange = function () {
    iframe.src = iframe.src + location.hash;
  };
</script>
登录后复制

3、c.html:(www.chuchur.com/c.html)

<script>
  // 监听b.html传来的hash值
  window.onhashchange = function () {
    // 再通过操作同域a.html的js回调,将结果传回
    window.parent.parent.test("你好: " + location.hash.replace("#nick=", ""));
  };
</script>
登录后复制

4)window.name + iframe跨域

原理:利用window.name特有属性,name值在不同的页面甚至不同域 ,当页面重新加载后依然存在,并且支持非常长的值,约 2MB

实现

// 1.)a.html:(www.chuchur.com/a.html)
var proxy = function (url, callback) {
  var state = 0;
  var iframe = document.createElement("iframe");
  // 加载跨域页面 ,先让页面的name执行赋值,
  iframe.src = url;
  // onload事件会触发2次,第1次加载跨域页,并留存数据于window.name
  iframe.onload = function () {
    if (state === 1) {
      // 第2次onload(同域proxy页)成功后,读取同域window.name中数据
      test(iframe.contentWindow.name);
      destoryFrame();
    } else if (state === 0) {
      // 第1次onload(跨域页)成功后,切换到同域代理页面
      iframe.contentWindow.location = "http://www.chuchur.com/b.html";
      state = 1;
    }
  };
  document.body.appendChild(iframe);
  // 获取数据以后销毁这个iframe,释放内存;这也保证了安全(不被其他域frame js访问)
  function destoryFrame() {
    iframe.contentWindow.document.write("");
    iframe.contentWindow.close();
    document.body.removeChild(iframe);
  }
};

// 请求跨域b页面数据
proxy("http://www.domain2.com/b.html", function (data) {
  alert(data);
});
// 2.)proxy.html:(www.chuchur.com/proxy.html), 这个页面可以什么都不写,但是要保证能正常访问
登录后复制
<!-- 3.)b.html:(www.chuchur.org/b.html) -->
<script>
  window.name = "我是一个可以非常长的变量";
</script>
登录后复制

5)postMessage跨域

postMessageHTML5 XMLHttpRequest Level 2中的API,可以解决以下方面的问题:

a.)页面和其打开的新窗口的数据传递

b.)多窗口之间消息传递

c.)页面与嵌套的iframe消息传递

d.)上面三个场景的跨域数据传递 用法:postMessage(data, origin)方法接受两个参数

data:html5规范支持任意基本类型或可复制的对象,但部分浏览器只支持字符串,所以传参时最好用JSON.stringify()序列化。

origin: 协议+主机+端口号,也可以设置为"\*",表示可以传递给任意窗口,如果要指定和当前窗口同源的话设置为"/"。

实现:

<!-- 1.)a.html:(www.chuchur.com/a.html) -->
<iframe
  id="iframe"
  src="http://www.chuchur.com/b.html"
  style="display:none; "
></iframe>
<script>
  var iframe = document.getElementById("iframe");
  iframe.onload = function () {
    var data = {
      name: "邱秋",
    };
    // 向chuchur.org传送跨域数据
    iframe.contentWindow.postMessage(
      JSON.stringify(data),
      "http://www.chuchur.org"
    );
  };

  // 接受chuchur.org返回数据
  window.addEventListener(
    "message",
    function (e) {
      alert("我来自chuchur.org: " + e.data);
    },
    false
  );
</script>
<!-- 2.)b.html:(www.chuchur.org/b.html) -->
<script>
  // 接收chuchur.com的数据
  window.addEventListener(
    "message",
    function (e) {
      alert("我来自chuchur.com " + e.data);
      var data = JSON.parse(e.data);
      if (data) {
        data.nick = chuchur;
        // 处理后再发回chuchur.com
        window.parent.postMessage(
          JSON.stringify(data),
          "http://www.chuchur.org"
        );
      }
    },
    false
  );
</script>
登录后复制

6)跨域资源共享(CORS

原理:普通跨域请求:只服务端设置Access-Control-Allow-Origin即可,前端无须设置。

cookie请求:前后端都需要设置字段,另外需注意:所带cookie为跨域请求接口所在域的cookie,而非当前页。 目前,所有浏览器都支持该功能(IE8+:IE8/9需要使用XDomainRequest对象来支持CORS),CORS也已经成为主流的跨域解决方案。

实现:

//1)原生js
var xhr = new XMLHttpRequest(); // IE8/9需用window. XDomainRequest兼容

// 前端设置是否带cookie
xhr.withCredentials = true;
xhr.open(&#39;post&#39;, &#39;http://www.chuchur.com/login&#39;, true);
xhr.setRequestHeader(&#39;Content-Type&#39;, &#39;application/x-www-form-urlencoded&#39;);
xhr.send(&#39;user=chuchur&#39;);
xhr.onreadystatechange = function() {

  if (xhr.readyState == 4 && xhr.status == 200) {
    alert(xhr.responseText);
  }

};
//2.)jQuery ajax
$.ajax({
  ...
  xhrFields: {
    withCredentials: true // 前端设置是否带cookie
  },
  crossDomain: true, // 会让请求头中包含跨域的额外信息,但不会含cookie
  ...
});
//3.)vue框架在vue-resource封装的ajax组件中加入以下代码:
Vue.http.options.credentials = true

//后台服务端
//java
/*
 * 导入包:import javax.servlet.http. HttpServletResponse;
 * 接口参数中定义:HttpServletResponse response
 */
response.setHeader("Access-Control-Allow-Origin", "http://www.chuchur.com"); // 若有端口需写全(协议+域名+端口)
response.setHeader("Access-Control-Allow-Credentials", "true");

//node
var server = http.createServer();
server.on(&#39;request&#39;, function(req, res) {
  var postData = &#39;&#39;;
  // 数据块接收中
  req.addListener(&#39;data&#39;, function(chunk) {
    postData += chunk;
  });

  // 数据接收完毕
  req.addListener(&#39;end&#39;, function() {
    postData = qs.parse(postData);
    // 跨域后台设置
    res.writeHead(200, {
      &#39;Access-Control-Allow-Credentials&#39;: &#39;true&#39;, // 后端允许发送Cookie
      &#39;Access-Control-Allow-Origin&#39;: &#39;http://www.chuchur.com&#39;, // 允许访问的域(协议+域名+端口)
      &#39;Set-Cookie&#39;: &#39;l=abcdef; Path=/; Domain=www.chuchur.com; HttpOnly&#39; // HttpOnly: 脚本无法读取cookie
    });

    res.write(JSON.stringify(postData));
    res.end();

  });

});
server.listen(&#39;3000&#39;);
登录后复制

7)nginx反向代理跨域

浏览器跨域访问jscssimg等常规静态资源被同源策略许可,但iconfont字体文件(eot|otf|ttf|woff|svg)例外,此时可在nginx的静态资源服务器中加入以下配置。

location / { add_header Access-Control-Allow-Origin *; }
登录后复制

原理:通过nginx代理一个 同域不同端口的跳板机,反向代理要跨域的域名,这样可以修改cookie里面的domain信息实现跨域

实现:

#nginx具体配置:
server {

    listen       80;
    server_name  www.chuchur.com;
    location / {
        proxy_pass   http://www.chuchur.org; #反向代理
        proxy_cookie_domain www.chuchur.org www.chuchur.com; #修改cookie里域名
        index  index.html index.htm;

        # 当用webpack-dev-server等中间件代理接口访问nignx时,此时无浏览器参与,故没有同源限制,下面的跨域配置可不启用
        add_header Access-Control-Allow-Origin http://www.chuchur.com; #当前端只跨域不带cookie时,可为*
        add_header Access-Control-Allow-Credentials true;
    }

}
登录后复制

前端实现

var xhr = new XMLHttpRequest();
// 前端开关:浏览器是否读写cookie
xhr.withCredentials = true;
// 访问nginx中的代理服务器
xhr.open(&#39;get&#39;, &#39;http://www.chuchur.com/?user=chuchur&#39;, true);
xhr.send();

// node
var http = require(&#39;http&#39;);
var server = http.createServer();
var qs = require(&#39;querystring&#39;);
server.on(&#39;request&#39;, function(req, res) {

  var params = qs.parse(req.url.substring(2));
  // 向前台写cookie
  res.writeHead(200, {

    &#39;Set-Cookie&#39;: &#39;l=abcdef; Path=/; Domain=www.chuchur.org; HttpOnly&#39; // HttpOnly: 脚本无法读取

  });
  res.write(JSON.stringify(params));
  res.end();

});
server.listen(&#39;8080&#39;);
登录后复制

8)Nodejs中间件代理跨域

原理同nignx代理跨域类似,都是通过代理服务器实现数据转发

实现:

//1)利用中间件http-proxy-middleware实现
var express = require(&#39;express&#39;);
var proxy = require(&#39;http-proxy-middleware&#39;);
var app = express();

app.use(&#39;/&#39;, proxy({

  // 代理跨域目标接口
  target: &#39;http://www.chuchur.org:&#39;,
  changeOrigin: true,
  // 修改响应头信息,实现跨域并允许带cookie
  onProxyRes: function(proxyRes, req, res) {

    res.header(&#39;Access-Control-Allow-Origin&#39;, &#39;http://www.chuchur.com&#39;);
    res.header(&#39;Access-Control-Allow-Credentials&#39;, &#39;true&#39;);

  },

  // 修改响应信息中的cookie域名
  cookieDomainRewrite: &#39;www.chuchur.com&#39; // 可以为false,表示不修改

}));

app.listen(3000);
//2)利用中间件 webpack-dev-server实现
//webpack.config.js部分配置:
module.exports = {
  entry: {},
  module: {},
  ...
  devServer: {
    historyApiFallback: true,
    proxy: [{
      context: &#39;/login&#39;,
      target: &#39;http://www.chuchur.org&#39;, // 代理跨域目标接口
      changeOrigin: true,
      cookieDomainRewrite: &#39;www.chuchur.com&#39; // 可以为false,表示不修改
    }],
    noInfo: true

  }
}
登录后复制

9)WebSocket协议跨域

WebSocket protocolHTML5一种新的协议。它实现了浏览器与服务器全双工通信,同时允许跨域通讯,是server push技术的一种很好的实现。原生WebSocket API使用起来不太方便,我们使用Socket.io,它很好地封装了webSocket接口,提供了更简单、灵活的接口,也对不支持webSocket的浏览器提供了向下兼容。

实现:

1、前端代码

<div>user input:<input type="text" /></div>
<script src="./socket.io.js"></script>
<script>
  var socket = io("http://www.chuchur.org");

  // 连接成功处理
  socket.on("connect", function () {
    // 监听服务端消息
    socket.on("message", function (msg) {
      console.log("来自服务器的消息: " + msg);
    });

    // 监听服务端关闭
    socket.on("disconnect", function () {
      console.log("Server socket has closed.");
    });
  });

  document.getElementsByTagName("input")[0].onblur = function () {
    socket.send(this.value);
  };
</script>
登录后复制

2、Nodejs socket后台:

var http = require(&#39;http&#39;);
var socket = require(&#39;socket.io&#39;);

// 启http服务
var server = http.createServer(function(req, res) {
  res.writeHead(200, {
    &#39;Content-type&#39;: &#39;text/html&#39;
  });
  res.end();
});

server.listen(&#39;8080&#39;);
console.log(&#39;Server is running at port 8080... &#39;);

// 监听socket连接
socket.listen(server).on(&#39;connection&#39;, function(client) {

      // 接收信息
      client.on(&#39;message&#39;, function(msg) {
          client.send(&#39;哈哈:&#39; + msg);
          console.log(&#39;来自客服端的消息&#39;: -- - > &#39; + msg);
          });

        // 断开处理
        client.on(&#39;disconnect&#39;, function() {
          console.log(&#39;Client socket has closed.&#39;);
        });

      });
登录后复制

以上 9 种方式都能实现跨域数据传递,用的最多的还是第六种跨域资源共享(CORS),在前后端分离开发模式最常见。第七种和第八种中间件代理实现方式则是在基于node开发种常用的

其中第二,三、四、五种方案 ,利用ifamepostMessage则可以实现 不同窗口之间的数据通讯。

【完】

推荐学习:H5视频教程

以上是你值得了解的WEB前端跨域解决方案(代码详解)的详细内容。更多信息请关注PHP中文网其他相关文章!

本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

AI Hentai Generator

AI Hentai Generator

免费生成ai无尽的。

热门文章

R.E.P.O.能量晶体解释及其做什么(黄色晶体)
4 周前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳图形设置
4 周前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您听不到任何人,如何修复音频
4 周前 By 尊渡假赌尊渡假赌尊渡假赌
WWE 2K25:如何解锁Myrise中的所有内容
1 个月前 By 尊渡假赌尊渡假赌尊渡假赌

热工具

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

PHP与Vue:完美搭档的前端开发利器 PHP与Vue:完美搭档的前端开发利器 Mar 16, 2024 pm 12:09 PM

PHP与Vue:完美搭档的前端开发利器在当今互联网高速发展的时代,前端开发变得愈发重要。随着用户对网站和应用的体验要求越来越高,前端开发人员需要使用更加高效和灵活的工具来创建响应式和交互式的界面。PHP和Vue.js作为前端开发领域的两个重要技术,搭配起来可以称得上是完美的利器。本文将探讨PHP和Vue的结合,以及详细的代码示例,帮助读者更好地理解和应用这两

前端面试官常问的问题 前端面试官常问的问题 Mar 19, 2024 pm 02:24 PM

在前端开发面试中,常见问题涵盖广泛,包括HTML/CSS基础、JavaScript基础、框架和库、项目经验、算法和数据结构、性能优化、跨域请求、前端工程化、设计模式以及新技术和趋势。面试官的问题旨在评估候选人的技术技能、项目经验以及对行业趋势的理解。因此,应试者应充分准备这些方面,以展现自己的能力和专业知识。

如何从驾驶舱Web用户界面启用管理访问 如何从驾驶舱Web用户界面启用管理访问 Mar 20, 2024 pm 06:56 PM

Cockpit是一个面向Linux服务器的基于Web的图形界面。它主要是为了使新用户/专家用户更容易管理Linux服务器。在本文中,我们将讨论Cockpit访问模式以及如何从CockpitWebUI切换Cockpit的管理访问。内容主题:驾驶舱进入模式查找当前驾驶舱访问模式从CockpitWebUI启用Cockpit的管理访问从CockpitWebUI禁用Cockpit的管理访问结论驾驶舱进入模式驾驶舱有两种访问模式:受限访问:这是驾驶舱的默认访问模式。在这种访问模式下,您不能从驾驶舱Web用户

web标准是什么东西 web标准是什么东西 Oct 18, 2023 pm 05:24 PM

Web标准是一组由W3C和其他相关组织制定的规范和指南,它包括HTML、CSS、JavaScript、DOM、Web可访问性和性能优化等方面的标准化,通过遵循这些标准,可以提高页面的兼容性、可访问性、可维护性和性能。Web标准的目标是使Web内容能够在不同的平台、浏览器和设备上一致地展示和交互,提供更好的用户体验和开发效率。

Django是前端还是后端?一探究竟! Django是前端还是后端?一探究竟! Jan 19, 2024 am 08:37 AM

Django是一个Python编写的web应用框架,它强调快速开发和干净方法。尽管Django是一个web框架,但是要回答Django是前端还是后端这个问题,需要深入理解前后端的概念。前端是指用户直接和交互的界面,后端是指服务器端的程序,他们通过HTTP协议进行数据的交互。在前端和后端分离的情况下,前后端程序可以独立开发,分别实现业务逻辑和交互效果,数据的交

C#开发经验分享:前端与后端协同开发技巧 C#开发经验分享:前端与后端协同开发技巧 Nov 23, 2023 am 10:13 AM

作为一名C#开发者,我们的开发工作通常包括前端和后端的开发,而随着技术的发展和项目的复杂性提高,前端与后端协同开发也变得越来越重要和复杂。本文将分享一些前端与后端协同开发的技巧,以帮助C#开发者更高效地完成开发工作。确定好接口规范前后端的协同开发离不开API接口的交互。要保证前后端协同开发顺利进行,最重要的是定义好接口规范。接口规范涉及到接口的命

PHP在Web开发中是属于前端还是后端? PHP在Web开发中是属于前端还是后端? Mar 24, 2024 pm 02:18 PM

PHP在Web开发中是属于后端。PHP是一种服务器端脚本语言,主要用于处理服务器端的逻辑,生成动态网页内容。与前端技术相比,PHP更多地用于与数据库交互、处理用户请求以及生成页面内容等后端操作。接下来通过具体的代码示例来说明PHP在后端开发中的应用。首先,我们来看一个简单的PHP代码示例,用于连接数据库并查询数据:

Go语言前端技术探秘:前端开发新视野 Go语言前端技术探秘:前端开发新视野 Mar 28, 2024 pm 01:06 PM

Go语言作为一种快速、高效的编程语言,在后端开发领域广受欢迎。然而,很少有人将Go语言与前端开发联系起来。事实上,使用Go语言进行前端开发不仅可以提高效率,还能为开发者带来全新的视野。本文将探讨使用Go语言进行前端开发的可能性,并提供具体的代码示例,帮助读者更好地了解这一领域。在传统的前端开发中,通常会使用JavaScript、HTML和CSS来构建用户界面

See all articles