Rumah  >  Artikel  >  hujung hadapan web  >  Penyelesaian merentas domain hadapan WEB yang anda patut ketahui (penjelasan kod terperinci)

Penyelesaian merentas domain hadapan WEB yang anda patut ketahui (penjelasan kod terperinci)

奋力向前
奋力向前ke hadapan
2021-09-06 10:12:374406semak imbas

Dalam artikel sebelumnya "Analisis ringkas tentang mampatan zip dan penyahmampatan zip dalam Node (dengan kod) ", saya memperkenalkan anda kepada penggunaan terperinci arahan mampatan zip dan penyahmampatan zip dalam Node . Artikel berikut akan memberi anda pemahaman tentang penyelesaian merentas domain bahagian hadapan WEB Datang dan lihat, kawan-kawan.

Penyelesaian merentas domain hadapan WEB yang anda patut ketahui (penjelasan kod terperinci)

Penyelesaian domain silang hujung hadapan WEB

Takrifan merentas domain

Takrifan luas: domain silang merujuk kepada domain Dokumen atau skrip cuba meminta sumber daripada domain lain.

1. Lompat sumber: pautan, ubah hala, penyerahan borang

2 Pembenaman sumber: 2cdf5bf648cf2f33323966d7f58a7f3f, 3f1c4e4b6b16bbbd69b2ee476dc4f83a, 79d7c95122630a3791db16c5259dc98d, 04a0d55efbbfd646a993fbc01f262c57 dan tag dom yang lain. serta pautan luaran ke fail seperti background:url() dan @font-face() dalam gaya

3. Permintaan skrip: js permintaan yang dimulakan oleh ajax, operasi merentas domain dom dan js objek, dsb.

Dasar asal sama

Dasar asal sama/SOP(Same origin policy) ialah konvensyen yang diperkenalkan ke dalam penyemak imbas oleh Netscape pada tahun 1995. Ia adalah teras dan paling asas ciri keselamatan penyemak imbas, jika dasar asal yang sama tiada, penyemak imbas akan terdedah kepada XSS, CSFR dan serangan lain. Asal yang dipanggil sama bermakna "protokol, nama domain dan port" adalah sama Walaupun dua nama domain yang berbeza menghala ke alamat ip yang sama, mereka bukan dari asal yang sama.

Dasar asal yang sama mengehadkan kelakuan berikut:

1, Cookie, LocalStorage dan IndexDB tidak boleh dibaca

2, DOM dan Js objek tidak boleh diperoleh

3 AJAXPermintaan tidak boleh dihantar

Penyelesaian merentas domain

Rentas domain1)jsonp

Mari kita fahami beberapa perkara tentang prinsip

: jsonp

1 Atribut

bagi teg html tidak mempunyai asal yang sama sekatan (menyokong domain silang), dan penyemak imbas menghuraikan tag src, sumber yang ditunjukkan oleh nilai atribut script (src) akan dimuat turun secara automatik url

2 ditunjukkan oleh tag

dimuat turun, kandungan akan dilaksanakan serta-merta; , dan kembalikan script ungkapan panggilan berbilang fungsi berdasarkan parameter ini Panggilan fungsi ini Parameter ungkapan ialah data yang ingin diperoleh oleh klien merentasi domain

4 dijana dan dikembalikan oleh pelayan, fungsi yang dipanggil oleh ungkapan telah ditakrifkan secara tempatan terlebih dahulu, dan parameter adalah Data yang dikehendaki diperoleh daripada pelayan merentas domain. Teg src literal boleh digunakan, seperti yang boleh ditambahkan secara dinamik pada pokok url yang terakhir adalah lebih mudah untuk acara yang mengikat. /

5. Ia hanya boleh mencapai

, yang juga merupakan kelemahannya scriptdomscript
Pencapaian:

get

2)
Rentas domain

// 服务端返回:
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);
  });
Prinsip

: Penyelesaian ini terhad kepada kes di mana domain utama ialah sama tetapi subdomain berbeza Prinsipnya ialah dua halaman dipaksa untuk menetapkan sebagai domain utama melalui document.domain iframe , dengan itu mencapai domain yang sama.

Pelaksanaan:

js3) window.domainMerentas 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>
Prinsip

: Prinsipnya adalah untuk lulus Lulus nilai, dan kemudian pantau perubahan nilai location.hash iframenya, kemudian gunakan lapisan tengah sebagai papan anjal, dan kemudian gunakan tetingkap ibu bapa-anak untuk akhirnya mengakses semua objek halaman dalam domain yang sama .

domain , domain , domain URL. hashjs parent

,

Domain yang berbeza hanya boleh berkomunikasi dengan menghantar nilai melalui 1: a.html. 2:b.html1:c.html

,

juga berada dalam domain yang berbeza dan hanya boleh berkomunikasi secara individu a.htmlb.htmlhash,

berada dalam domain yang sama, jadi

boleh diakses melalui b.htmlc.htmlObjek halaman

a.html melaksanakan c.html: c.htmlparenta.html1,

2, 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>
`

3, 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>

4) Rentas domainc.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>
Prinsip

: Menggunakan atribut unik , nilai window.name iframe akan tetap wujud pada halaman yang berbeza atau bahkan domain yang berbeza apabila halaman dimuat semula dan menyokong sangat lama nilai, kira-kira .

Pelaksanaan:window.namename2MB

5)Rentas domain

// 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>
Ya dalam 🎜> boleh menyelesaikan masalah berikut: postMessagePemindahan data antara halaman dan tetingkap baharu yang dibukanya

postMessagePemindahan mesej antara berbilang tetingkapHTML5 XMLHttpRequest Level 2

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视频教程

Atas ialah kandungan terperinci Penyelesaian merentas domain hadapan WEB yang anda patut ketahui (penjelasan kod terperinci). Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Kenyataan:
Artikel ini dikembalikan pada:chuchur.com. Jika ada pelanggaran, sila hubungi admin@php.cn Padam