资讯专栏INFORMATION COLUMN

「跨域」利用node.js实践前端各种跨域方式(上)

Lavender / 250人阅读

摘要:如果对你有帮助的话,欢迎一跨域首先我们在本地起一个服务器,用于接收客户端的请求并作出回应。五跨域原理域想和域通信,通过中间页面。即借助接收到了发来的消息,并给予回应跨域成功接下文跨域利用实践前端各种跨域方式下

前言

常言道,"读万卷书,不如行万里路"。技术的学习也是如此,唯有实践才能更清楚的明白原理和加深印象,因此本文会利用node.js对前端的各种跨域方式进行实践,强烈建议一步一步跟着做,相信你肯定会对跨域有更深层次的理解。而由于篇幅限制,本文只会贴出关键性的代码,本系列总共分为上下篇。具体的代码请移步我的Github。如果对你有帮助的话,欢迎 star ヾ(´・ω・`)ノ

一、cors 跨域

首先我们在本地起一个服务器,用于接收客户端的请求并作出回应。

//目录:cors/server.js

const http = require("http");

http.createServer(function (req, res) {
    //设置响应头部
    res.writeHead(200, {"Content-Type": "text/plain"});
    res.write("This is a server page");
    res.end();
  }).listen(3333);
   console.log("server start!")

然后,开启另一个服务,服务里加载一个html页面,页面对发出xhr请求,模拟浏览器对服务器的请求。

//目录:cors/clientServer.js

const express = require("express");
const app = express();

app.use(express.static("./public"));
app.listen(3000)
console.log("client server start");

//目录:cors/public/client.html

            const  content = document.getElementById("content");

            const xhr = new XMLHttpRequest();
            xhr.withCredentials = true;
            xhr.onload = function(){
                if(xhr.readyState == 4) {
                    if(xhr.status >= 200 && xhr.status <300 || xhr.status == 304) {
                        content.innerHTML = "Reuqest was success:" + xhr.responseText;
                        console.log("Request was success:", xhr.responseText);
                    }else {
                        content.innerHTML = "Reuqest was failed:" + xhr.status;
                        console.log("Request was failed:", xhr.status); 
                    }
                }
            }
            // xhr.open("get", "http://localhost:3000/client.html", true); //不跨域
            xhr.open("get", "http://localhost:3333", true); //跨域

            xhr.send();

分别运行两个服务,测试3000和3333接口,发现只有跨域的时候,请求的头部才会带着origin字段。此时我们修改cors/server.js, 加上这行代码:

    res.setHeader("Access-Control-Allow-Origin", "http://localhost:3000");

这行代码代表服务器允许接收来自3000接口的请求,此时客户端再次请求服务器,就能在用户毫无感知的情况下完成跨域。

而此时如果想让客户端带cookie请求呢?那么需要做以下工作:

1.cors/server.js 加上这行

    res.setHeader("Access-Control-Allow-Credentials", true);

2.cors/public/client.html 加上这行

xhr.withCredentials = true;

然后,你就会发现,客户端会把当前域下的cookie一起发给服务器啦╮( ̄▽ ̄")╭

ps:注意cookie只能细分到域名下,不能细分到端口。即没办法设置一个cookie仅在localhost:xxxx下。尽管端口不同会被浏览器认为不同源。
二、jsonp跨域

通常为了减轻web服务器的负载,我们把js、css,img等静态资源分离到另一台独立域名的服务器上,在html页面中再通过相应的标签从不同域名下加载静态资源,而被浏览器允许,基于此原理,我们可以通过动态创建script,再请求一个带参网址实现跨域通信。

下面这个例子采用jQuery中的ajax方法,与服务器端约定将数据回传到回调函数中,比如本例中的callback=person,然后我们就可以从回调函数person里获取服务器传给浏览器的数据了。另外,jsonp的缺点就是只能采用get请求。

1.目录:jsonp/server.js

const http = require("http");
const urllib = require("url");
const  httpdispatcher = require("httpdispatcher");
const dispatcher = new httpdispatcher();

const PORT = 1112;

function handleRequest(req, res) {
    try {
        console.log(req.url);

        dispatcher.dispatch(req, res);
    }catch(err) {
        console.log(err);
    }
}

const server = http.createServer(handleRequest);

dispatcher.onGet("/getPerson", function (req, res, next) {
  const data = {"name": "Jchermy", "company": "dog company"};
  const params = urllib.parse(req.url, true);

  if(params.query && params.query.callback) {
      let str = `${params.query.callback}(${JSON.stringify(data)})`;
      res.write(str);
      res.end();
  }else {
      res.write(JSON.stringify(data));
      res.end();
  }
})

server.listen(PORT, function () {
    console.log("server listening on http://localhost: %s", PORT);
  })

2.目录:jsonp/client.js

const express = require("express");
const app = express();

app.use(express.static("./public"));
app.listen(1111);
console.log("client start");

3.目录:jsonp/public/index.html




    
    
    
    index
    


    
    
姓名:
公司:

分别运行客户端和服务端,点击“获取跨域数据的按钮”,当前页面(1111端口)就可以拿到1112端口的数据啦~~(●′ω`●)

三、document.domain + frame 跨域

此方案仅限主域相同,子域不同的跨域应用场景。

实现原理:两个页面都通过js强制设置document.domain为基础主域,就实现了同域。

下面只是举个例子帮助大家理解一下。

现在有两个网址。百度知道和百度百科

https://zhidao.baidu.com/
https://baike.baidu.com/

在百度知道的网页,写下以下命令:

document.domain = "baidu.com";
const child= window.open("https://baike.baidu.com/");

在打开的百度百科的网页,写下以下命令:

document.domain = "baidu.com";

然后回到百度知道的网页,就可以获取到百度百科(子页面)的元素啦:

const button = other.document.getElementById("search");

//
四、window.name+iframe 跨域
window.name属性的独特之处:name值在不同的页面(甚至不同域名)加载后依旧存在,并且可以支持非常长的 name 值(2MB)。

在本地起两个node服务,分别占用3333和4444。父页面是:
1.window-name/public/index.html

          const proxy = function(url ,callback) {
                let status = 0;
                const iframe = document.createElement("iframe");

                iframe.src = url;

                iframe.onload = function(){
                    if(status === 1) {
                        callback(iframe.contentWindow.name);
                        destoryFrame();
                    } else if (status === 0) {
                        iframe.contentWindow.location = "http://localhost:4444/proxy.html";
                        status = 1;
                    }
                }

                document.body.appendChild(iframe);
          };
         

          function destoryFrame() {
              iframe.contentWindow.document.write("");
              iframe.contentWindow.close();
              document.body.removeChild(iframe);
          }

          proxy("http://localhost:3333/iframe.html", function(data) {
              alert(data);
          })

2.iframe 页面是
window-name/public/iframe.html

    

3.还有一个代理页面,跟父页面同源。内容为空就好。目录:/window-name/public/proxy.html

总结:通过iframe的src属性由外域转向本地域,跨域数据即由iframe的window.name从外域传递到本地域。这个就巧妙地绕过了浏览器的跨域访问限制,但同时它又是安全操作。

五、location.hash+iframe 跨域

原理:A域想和B域通信,通过中间页面c。不同域之间通过location.hash来通信,而相同域之间直接通过js来通信。

实现:A域:a.html ----> B域:b.html ----> A域:c.html,a与b不同域只能通过hash值单向通信,b与c也不同域也只能单向通信,但c与a同域,所以c可通过parent.parent访问a页面所有对象。

目录:location-hash/public/a.html




    
    
    
    a
    


    

目录:location-hash/public/b.html




    
    
    
    b
    


    


目录:location-hash/public/c.html

    

然后,我们通过node服务将a.html和c.html部署在同一个端口下,将b.html部署在另一个端口。

//location-hash/server1.js
app.use("/a.html", express.static(__dirname+"/public/a.html"));
app.use("/c.html", express.static(__dirname+"/public/c.html"));
app.listen(3333);

//location-hash/server2.js
app.use("/b.html", express.static(__dirname+"/public/b.html"));
app.listen(4444);

最后,我们分别将两个服务跑起来。访问localhost:3333可以看到弹窗。

即b.html借助c.html接收到了a.html发来的消息,并给予回应"hello admin",跨域成功~

接下文--->「跨域」利用node.js实践前端各种跨域方式(下)

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

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

相关文章

  • 跨域利用node.js实践前端各种跨域方式

    摘要:如果对你有帮助的话,欢迎一跨域首先我们在本地起一个服务器,用于接收客户端的请求并作出回应。五跨域原理域想和域通信,通过中间页面。即借助接收到了发来的消息,并给予回应跨域成功接下文跨域利用实践前端各种跨域方式下 前言 常言道,读万卷书,不如行万里路。技术的学习也是如此,唯有实践才能更清楚的明白原理和加深印象,因此本文会利用node.js对前端的各种跨域方式进行实践,强烈建议一步一步跟着做...

    jaysun 评论0 收藏0
  • 跨域利用node.js实践前端各种跨域方式(下)

    摘要:技术的学习也是如此唯有实践才能更清楚的明白原理和加深印象,因此本文会利用对前端的各种跨域方式进行实践,强烈建议一步一步跟着做,相信你肯定会对跨域有更深层次的理解。 前言 常言道,读万卷书,不如行万里路。技术的学习也是如此,唯有实践才能更清楚的明白原理和加深印象,因此本文会利用node.js对前端的各种跨域方式进行实践,强烈建议一步一步跟着做,相信你肯定会对跨域有更深层次的理解。而由于篇...

    Jenny_Tong 评论0 收藏0
  • 前端相关大杂烩

    摘要:希望帮助更多的前端爱好者学习。前端开发者指南作者科迪林黎,由前端大师倾情赞助。翻译最佳实践译者张捷沪江前端开发工程师当你问起有关与时,老司机们首先就会告诉你其实是个没有网络请求功能的库。 前端基础面试题(JS部分) 前端基础面试题(JS部分) 学习 React.js 比你想象的要简单 原文地址:Learning React.js is easier than you think 原文作...

    fuyi501 评论0 收藏0
  • 20170917 前端开发周报:JavaScript函数式编程、作用域和闭包

    摘要:用函数式编程对进行断舍离当从业的老司机学会函数式编程时,他扔掉了的特性,也不用面向对象了,最后发现了真爱啊作用域和闭包作用域和闭包在里非常重要。旨在帮助非函数式编程的同学,能快速切入到函数式编程的理念。 1、用函数式编程对JavaScript进行断舍离 当从业20的JavaScript老司机学会函数式编程时,他扔掉了90%的特性,也不用面向对象了,最后发现了真爱啊!!! https:/...

    tomener 评论0 收藏0
  • 20170917 前端开发周报:JavaScript函数式编程、作用域和闭包

    摘要:用函数式编程对进行断舍离当从业的老司机学会函数式编程时,他扔掉了的特性,也不用面向对象了,最后发现了真爱啊作用域和闭包作用域和闭包在里非常重要。旨在帮助非函数式编程的同学,能快速切入到函数式编程的理念。 1、用函数式编程对JavaScript进行断舍离 当从业20的JavaScript老司机学会函数式编程时,他扔掉了90%的特性,也不用面向对象了,最后发现了真爱啊!!! https:/...

    cyixlq 评论0 收藏0

发表评论

0条评论

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