前端通信、跨域

首先了解什么是同源策略:

限制一个源加载的文档或脚本与来自另一个源的资源进行交互。这是一个用于隔离潜在恶意文件的关键的安全机制。(来自MDN的解释)

源包括三个部分:协议、域名、端口(HTTP协议的默认端口是80)。如果其中有任何一个部分不同,则源不同。即为跨域。

限制:这个源的文档没有权利去操作另一个源的文档。这个限制体现在:

Cookie、LlocalStorage和IndexDB无法获取;

无法获取和操作DOM;

不能发送Ajax请求。(Ajax只适合同源的通信)。

前后端的通信方式:

Ajax:不支持跨域;

WebSocket:不受同源策略的限制,支持跨域;

CORS:不受同源策略的限制,支持跨域;一种新的通信协议标准。可以理解成同时支持同源和跨域的Ajax。

如何创建Ajax:

在回答 Ajax 的问题时,要回答以下几个方面:

  • 1、XMLHttpRequest 的工作原理
  • 2、兼容性处理

XMLHttpRequest只有在高级浏览器中才支持。在回答问题时,这个兼容性问题不要忽略。

  • 3、事件的出发条件
  • 4、事件的触发顺序

XMLHttpRequest有很多触发事件,每个事件是怎么触发的。

发送Ajax请求的五个步骤(XMLHttpRequest的工作原理)

1.创建XMLHttpRequest对象;

2.使用open方法设置请求的参数。open(method,url,是否异步)

3.发送请求;

4.注册事件。使用onreadystatechange事件,状态改变时就会调用。如果要在数据完整请求返回才调用需要加一些状态判断;

5.获取返回的数据,更新UI

发送get请求和post请求:
get请求举例:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<body>
<h1>Ajax 发送 get 请求</h1>
<input type="button" value="发送get_ajax请求" id=‘btnAjax‘>

<script type="text/javascript">
    // 绑定点击事件
    document.querySelector(‘#btnAjax‘).onclick = function () {
        // 发送ajax 请求 需要 五步

        // (1)创建异步对象
        var ajaxObj = new XMLHttpRequest();

        // (2)设置请求的参数。包括:请求的方法、请求的url。
        ajaxObj.open(‘get‘, ‘02-ajax.php‘);

        // (3)发送请求
        ajaxObj.send();

        //(4)注册事件。 onreadystatechange事件,状态改变时就会调用。
        //如果要在数据完整请求回来的时候才调用,我们需要手动写一些判断的逻辑。
        ajaxObj.onreadystatechange = function () {
            // 为了保证 数据 完整返回,我们一般会判断 两个值
            if (ajaxObj.readyState == 4 && ajaxObj.status == 200) {
                // 如果能够进到这个判断 说明 数据 完美的回来了,并且请求的页面是存在的
                // 5.在注册的事件中 获取 返回的 内容 并修改页面的显示
                console.log(‘数据返回成功‘);

                // 数据是保存在 异步对象的 属性中
                console.log(ajaxObj.responseText);

                // 修改页面的显示
                document.querySelector(‘h1‘).innerHTML = ajaxObj.responseText;
            }
        }
    }
</script>
</body>
</html>

post请求举例:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<body>
<h1>Ajax 发送 get 请求</h1>
<input type="button" value="发送put_ajax请求" id=‘btnAjax‘>
<script type="text/javascript">

    // 异步对象
    var xhr = new XMLHttpRequest();

    // 设置属性
    xhr.open(‘post‘, ‘02.post.php‘);

    // 如果想要使用post提交数据,必须添加此行
    xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");

    // 将数据通过send方法传递
    xhr.send(‘name=fox&age=18‘);

    // 发送并接受返回值
    xhr.onreadystatechange = function () {
        // 这步为判断服务器是否正确响应
        if (xhr.readyState == 4 && xhr.status == 200) {
            alert(xhr.responseText);
        }
    };
</script>
</body>
</html>

onreadystatechange事件:

注册onreadystatechange事件后,每当readyState属性改变时,就会调用onreadystatechange函数。

readyState:(存有XMLHttpRequest的状态。从0到4变化)

0:请求未初始化;

1:服务器连接已建立;

2:请求已接收;

3:请求处理中;

4:请求已完成,且响应已就绪

事件的触发条件

事件的触发顺序

原生Ajax请求

 var util = {};

    //获取 ajax 请求之后的json
    util.json = function (options) {

        var opt = {
            url: ‘‘,
            type: ‘get‘,
            data: {},
            success: function () {
            },
            error: function () {
            },

        };
        util.extend(opt, options);
        if (opt.url) {
            //IE兼容性处理:浏览器特征检查。检查该浏览器是否存在XMLHttpRequest这个api,没有的话,就用IE的api
            var xhr = XMLHttpRequest ? new XMLHttpRequest() : new window.ActiveXObject(‘Microsoft.XMLHTTP‘);

            var data = opt.data,
                url = opt.url,
                type = opt.type.toUpperCase();
            dataArr = [];
        }

        for (var key in data) {
            dataArr.push(key + ‘=‘ + data[key]);
        }

        if (type === ‘GET‘) {
            url = url + ‘?‘ + dataArr.join(‘&‘);
            xhr.open(type, url.replace(/\?$/g, ‘‘), true);
            xhr.send();
        }

        if (type === ‘POST‘) {
            xhr.open(type, url, true);
            // 如果想要使用post提交数据,必须添加此行
            xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
            xhr.send(dataArr.join(‘&‘));
        }

        xhr.onload = function () {
            if (xhr.status === 200 || xhr.status === 304) { //304表示:用缓存即可。206表示获取媒体资源的前面一部分
                var res;
                if (opt.success && opt.success instanceof Function) {
                    res = xhr.responseText;
                    if (typeof res === ‘string‘) {
                        res = JSON.parse(res);  //将字符串转成json
                        opt.success.call(xhr, res);
                    }
                }
            } else {
                if (opt.error && opt.error instanceof Function) {
                    opt.error.call(xhr, res);
                }
            }
        };
    }

跨域通信的几种方式:

1.JSONP

2.WebSocket

3.CORS

4.Hash

5.postMessage

1.JSONP

原理:通过<script>标签的异步加载来实现。例如通过<script>标签的src,里面放url,加载一些插件,就用到JSONP。

实现:<script src="http://www.smyhvae.com/?data=name&callback=myjsonp"></script>

上面的src中,data=name是get请求的参数,myjsonp是和后台约定好的函数名。

服务器端这样写:

myjsonp({
            data: {}

        })

于是,本地要求创建一个myjsonp 的全局函数,才能将返回的数据执行出来。

实际开发中前端的JSONP的实现:

<script>

    var util = {};

    //定义方法:动态创建 script 标签
    /**
     * [function 在页面中注入js脚本]
     * @param  {[type]} url     [description]
     * @param  {[type]} charset [description]
     * @return {[type]}         [description]
     */
    util.createScript = function (url, charset) {
        var script = document.createElement(‘script‘);
        script.setAttribute(‘type‘, ‘text/javascript‘);
        charset && script.setAttribute(‘charset‘, charset);
        script.setAttribute(‘src‘, url);
        script.async = true;
        return script;
    };

    /**
     * [function 处理jsonp]
     * @param  {[type]} url      [description]
     * @param  {[type]} onsucess [description]
     * @param  {[type]} onerror  [description]
     * @param  {[type]} charset  [description]
     * @return {[type]}          [description]
     */
    util.jsonp = function (url, onsuccess, onerror, charset) {
        var callbackName = util.getName(‘tt_player‘); //事先约定好的 函数名
        window[callbackName] = function () {      //根据回调名称注册一个全局的函数
            if (onsuccess && util.isFunction(onsuccess)) {
                onsuccess(arguments[0]);
            }
        };
        var script = util.createScript(url + ‘&callback=‘ + callbackName, charset);   //动态创建一个script标签
        script.onload = script.onreadystatechange = function () {   //监听加载成功的事件,获取数据
            if (!script.readyState || /loaded|complete/.test(script.readyState)) {
                script.onload = script.onreadystatechange = null;
                // 移除该script的 DOM 对象
                if (script.parentNode) {
                    script.parentNode.removeChild(script);
                }
                // 删除函数或变量
                window[callbackName] = null;  //最后不要忘了删除
            }
        };
        script.onerror = function () {
            if (onerror && util.isFunction(onerror)) {
                onerror();
            }
        };
        document.getElementsByTagName(‘head‘)[0].appendChild(script); //往html中增加这个标签,目的是把请求发送出去
    };

</script>

2.WebSocket

代码实例如下:

    var ws = new WebSocket(‘wss://echo.websocket.org‘); //创建WebSocket的对象。参数可以是 ws 或 wss,后者表示加密。

    //把请求发出去
    ws.onopen = function (evt) {
        console.log(‘Connection open ...‘);
        ws.send(‘Hello WebSockets!‘);
    };

    //对方发消息过来时,我接收
    ws.onmessage = function (evt) {
        console.log(‘Received Message: ‘, evt.data);
        ws.close();
    };

    //关闭连接
    ws.onclose = function (evt) {
        console.log(‘Connection closed.‘);
    };

3.CORS

fetch是一个比较新的API,用来实现CORS通信。用法如下:

// url(必选),options(可选)
      fetch(‘/some/url/‘, {
          method: ‘get‘,
      }).then(function (response) {  //类似于 ES6中的promise

      }).catch(function (err) {
        // 出错了,等价于 then 的第二个参数,但这样更好用更直观
      });

另外,如果面试官问:“CORS为什么支持跨域的通信?”

答案:跨域时,浏览器会拦截Ajax请求,并在http头中加Origin。

4.Hash

url的#后面的内容就叫Hash。Hash的改变,页面不会刷新。这就是用 Hash 做跨域通信的基本原理。

补充:url的?后面的内容叫Search。Search的改变,会导致页面刷新,因此不能做跨域通信。

场景:我的页面 A 通过iframe或frame嵌入了跨域的页面 B。

现在,我这个A页面想给B页面发消息,怎么操作呢?

(1)首先,在我的A页面中:

 //伪代码
    var B = document.getElementsByTagName(‘iframe‘);
    B.src = B.src + ‘#‘ + ‘jsonString‘;  //我们可以把JS 对象,通过 JSON.stringify()方法转成 json字符串,发给 B

(2)然后,在B页面中:

// B中的伪代码
    window.onhashchange = function () {  //通过onhashchange方法监听,url中的 hash 是否发生变化
        var data = window.location.hash;
    };

5.postMessage()方法

场景:窗口 A (http:A.com)向跨域的窗口 B (http:B.com)发送信息。步骤如下。

(1)在A窗口中操作如下:向B窗口发送数据:

// 窗口A(http:A.com)向跨域的窗口B(http:B.com)发送信息
    Bwindow.postMessage(‘data‘, ‘http://B.com‘); //这里强调的是B窗口里的window对象

(2)在B窗口中操作如下:

// 在窗口B中监听 message 事件
    Awindow.addEventListener(‘message‘, function (event) {   //这里强调的是A窗口里的window对象
        console.log(event.origin);  //获取 :url。这里指:http://A.com
        console.log(event.source);  //获取:A window对象
        console.log(event.data);    //获取传过来的数据
    }, false);

参考:

https://www.cnblogs.com/smyhvae/p/8523576.html

原文地址:https://www.cnblogs.com/lhh520/p/10198283.html

时间: 2024-10-17 16:01:10

前端通信、跨域的相关文章

前端解决跨域问题的8种方案(最新最全)

原文:http://www.cnblogs.com/JChen666/p/3399951.html 1.同源策略如下: URL 说明 是否允许通信 http://www.a.com/a.jshttp://www.a.com/b.js 同一域名下 允许 http://www.a.com/lab/a.jshttp://www.a.com/script/b.js 同一域名下不同文件夹 允许 http://www.a.com:8000/a.jshttp://www.a.com/b.js 同一域名,不同端

前端解决跨域问题的8种方案(最新最全)(转)

1.同源策略如下: URL说明是否允许通信 http://www.a.com/a.jshttp://www.a.com/b.js同一域名下允许 http://www.a.com/lab/a.jshttp://www.a.com/script/b.js同一域名下不同文件夹允许 http://www.a.com:8000/a.jshttp://www.a.com/b.js同一域名,不同端口不允许 http://www.a.com/a.jshttps://www.a.com/b.js同一域名,不同协议

前端解决跨域问题的8种方案

原文http://blog.csdn.net/joyhen/article/details/21631833 1.同源策略如下: URL 说明 是否允许通信 http://www.a.com/a.jshttp://www.a.com/b.js 同一域名下 允许 http://www.a.com/lab/a.jshttp://www.a.com/script/b.js 同一域名下不同文件夹 允许 http://www.a.com:8000/a.jshttp://www.a.com/b.js 同一域

前端常见跨域解决方案(全)

什么是跨域? 跨域是指一个域下的文档或脚本试图去请求另一个域下的资源,这里跨域是广义的. 广义的跨域: 1.) 资源跳转: A链接.重定向.表单提交 2.) 资源嵌入: <link>.<script>.<img>.<frame>等dom标签,还有样式中background:url().@font-face()等文件外链 3.) 脚本请求: js发起的ajax请求.dom和js对象的跨域操作等 其实我们通常所说的跨域是狭义的,是由浏览器同源策略限制的一类请求场

前端常见跨域解决方案

什么是跨域? 跨域是指一个域下的文档或脚本试图去请求另一个域下的资源,这里跨域是广义的. 广义的跨域: 1.) 资源跳转: A链接.重定向.表单提交 2.) 资源嵌入:<link>.<script>.<img>.<frame>等dom标签,还有样式中background:url().@font-face()等文件外链 3.) 脚本请求: js发起的ajax请求.dom和js对象的跨域操作等 其实我们通常所说的跨域是狭义的,是由浏览器同源策略限制的一类请求场景

前端解决跨域问题的8种方案(转)

前端解决跨域问题的8种方案(最新最全) 原文:http://www.cnblogs.com/JChen666/p/3399951.html 1.同源策略如下: URL 说明 是否允许通信 http://www.a.com/a.jshttp://www.a.com/b.js 同一域名下 允许 http://www.a.com/lab/a.jshttp://www.a.com/script/b.js 同一域名下不同文件夹 允许 http://www.a.com:8000/a.jshttp://www

(转)前端解决跨域问题的8种方案(最新最全)

转:http://www.cnblogs.com/JChen666/p/3399951.html 1.同源策略如下: URL 说明 是否允许通信 http://www.a.com/a.jshttp://www.a.com/b.js 同一域名下 允许 http://www.a.com/lab/a.jshttp://www.a.com/script/b.js 同一域名下不同文件夹 允许 http://www.a.com:8000/a.jshttp://www.a.com/b.js 同一域名,不同端口

前端Jquery-Ajax跨域请求,并携带cookie

目录 1. 需现在服务端允许跨域,允许携带cookie 2. 前端Ajax跨域请求代码 1. 需现在服务端允许跨域,允许携带cookie 因服务端脚本语言不同,自行搜索设置 2. 前端Ajax跨域请求代码 $.ajax({ type: "POST", url: "http://127.0.0.1:8000/api/login", data: JSON.stringify({'num': 1}), dataType: 'json', xhrFields: { with

跨域通信/跨域上传浅析

web项目跨域问题主要包括跨域通信和跨域上传,下面对这两方面分别做一个分析,具体项目中用哪个方案要看项目具体需求. 跨域通信 jsonp hash server proxy window.name cors postmessage redirect jsonp 原理:发起一个GET请求,回调函数带到请求参数中,把数据发送过去 坏处:服务器需要支持jsoncallback参数 好处:业界比较通用的方案,包括打点等操作都可以用类似技术 浏览器支持:chrome/firefox/safari/oper

运用 node + express + http-proxy-middleware 实现前端代理跨域的 详细实例哦

一.你需要准备的知识储备 运用node的包管理工具npm 安装插件.中间件的基本知识: 2.express框架的一些基础知识,知道如何建立一个小的服务器:晓得如何快速的搭建一个express框架小应用: 3.还需要一些前端的基础小知识,html\css\js\jquery 4.最重要的一点就是知道怎么产生的跨域,要是不知道怎么产生的跨域,如何知道需要去破解它呢? 二.实例的代码分析 场景分析,我本地的域名为<http.localhost:8080>,我要请求的地址是<http.****.