ajax

Posted 郭东东郭

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ajax相关的知识,希望对你有一定的参考价值。

一、ajax 原理 和 使用

ajax,即在不重新加载整个网页的情况下,对网页的某部分进行更新。

下面演示ajax 的实现原理

配置:

cd ajax

参考:http://www.expressjs.com.cn/starter/generator.html

express --view=ejs myapp
cd myapp
npm install

1、完整的ajax流程:

(1)、 创建XMLHttpRequest对象

var xhr = new XMLHttpRequest();

(2)、准备发送

 xhr.open(\'get\', \'./01check.js?username=\'+uname+\'&password=\'+pw,true);

(3)、执行发送动作

 xhr.send(null);

(4)、监听response 回调函数

onreadystatechange 事件:每当 readyState 改变时,就会触发 onreadystatechange 事件。

2、代码逻辑

index.js 路由

......
router.get(\'/api/one\',(req,res,next)=>{
  res.json({
      status:200,
      result:\'this is one.....\'
  })
});


/* GET home page. */
router.get(\'/one\', function(req, res, next) {
  res.render(\'index1\', { title: \'Express\' });
})
...........

index.ejs:

<body>
<button id="send">发送1个请求</button>
<script>
  var btn = document.getElementById(\'send\');
  btn.addEventListener(\'click\',function () {
     // 使用原生的ajax 技术,发送一个网络请求
      // 1.创建XMLHttpRequest对象
      var xhr;
      if(window.XMLHttpRequest){
          xhr = new XMLHttpRequest();
      }else {
          xhr = new ActiveXObject(\'Microsoft.XMLHTTP\');
      }

      // 2.准备发送
      /*
       参数1: 请求方式 (get/post)
       参数2: 请求url
       参数3: 是否异步
    */
      xhr.open(\'get\',\'http://localhost:3000/api/one\',true);

      // 3. 发送
    xhr.send();

      // 4. 监听服务器的响应
      // 一旦服务器响应回来之后, 就会执行这个函数
      xhr.onreadystatechange = function () {
          console.log(xhr.readyState);
          if(xhr.readyState === 4){  // 代表服务器已经给了响应, 不代表响应成功
              if(xhr.status === 200){
                  console.log(xhr.response);
              }
          }
      }

  });
</script>
</body>

// 结果:
/*
2
3
4
{"status":200,"result":"this is one....."}
*/


index.js 路由:

router.get(\'/api/two\',(req,res,next)=>{
    console.log(req.query);
    res.json({
        status:200,
        result:\'this is two.....\'
    })
});


router.get(\'/two\', function(req, res, next) {
    res.render(\'index2\', { title: \'Express\' });
});

index2.ejs

<body>
<input id="account" type="text" name="account">
<input id="pwd" type="text" name="pwd">
<button id="send">发送一个请求</button>
<script>
    window.onload=function () {

        var btn = document.getElementById(\'send\');
        btn.onclick = function () {
            // 使用原生的ajax 技术,发送一个网络请求
            // 1.创建XMLHttpRequest对象
            var xhr;
            if(window.XMLHttpRequest){
                xhr = new XMLHttpRequest();
            }else {
                xhr = new ActiveXObject(\'Microsoft.XMLHTTP\');
            }

            // 从页面获取需要传递的数据
            var userName = document.getElementById(\'account\').value;
            var pwd = document.getElementById(\'pwd\').value;

            // 2.准备发送
            /*
             参数1: 请求方式 (get/post)
             参数2: 请求url
             参数3: 是否异步
          */
            // 后面跟一个随机数值,保证每次发送ajax请求,都是真的发然后从响应中获取最新数据,而不是从缓存中取得
            xhr.open(\'get\', \'http://localhost:3000/api/two?account=\' + account + \'&pwd=\' + pwd + \'&random=\' + getRandomStr(), true);

            // 3. 发送
            xhr.send();

            // 4. 监听服务器的响应
            // 一旦服务器响应回来之后, 就会执行这个函数
            xhr.onreadystatechange = function () {
                // 5. 处理响应的数据 (对方说话)
                console.log(xhr.readyState);
                if(xhr.readyState === 4){  // 代表服务器已经给了响应, 不代表响应成功
                    if(xhr.status === 200){
                        console.log(xhr.response);
                    }
                }
            }
        }
    }


    function getRandomStr() {
        return Math.random() + (new Date().getTime())
    }
</script>

</body>

前端打印:

2
3
4
{"status":200,"result":"this is two....."}

服务端打印:

{ account: \'[object htmlInputElement]\',
  pwd: \'123456\',
  random: \'1547356096169.2708\' }
GET /api/two?account=[object%20HTMLInputElement]&pwd=123456&random=1547356096169.2708 200 8.824 ms - 42


封装ajax:

AjaxTool.js:

(function (window) {
    function AjaxTool() {}

    AjaxTool.ajaxRequest = function (url, paramObj, timeout, successCallBack, errorCallBack) {
        // 1.创建XMLHttpRequest对象
        var xhr;
        if(window.XMLHttpRequest){
            xhr = new XMLHttpRequest();
        }else {
            xhr = new ActiveXObject(\'Microsoft.XMLHTTP\');
        }


        // 2.准备发送
        /*
         参数1: 请求方式 (get/post)
         参数2: 请求url
         参数3: 是否异步
      */
        // 后面跟一个随机数值,保证每次发送ajax请求,都是真的发然后从响应中获取最新数据,而不是从缓存中取得
        var params_str = getStrWithObj(paramObj);
        var uri_str = url + \'?\' + params_str;
        // 转码
        var codeURI = encodeURI(uri_str)
        xhr.open(\'get\', codeURI, true);


        // 3. 发送
        xhr.send();

        // 4. 监听服务器的响应
        xhr.onreadystatechange = function () {
            // 5. 处理响应的数据
            console.log(xhr.readyState);
            if(xhr.readyState === 4){  // 代表服务器已经给了响应, 不代表响应成功
                if(xhr.status === 200){
                    successCallBack(xhr);
                }else {
                    errorCallBack();

                }
            }
        }

        // 5. 控制请求的时间
        var timer;
        if(timeout > 0){
            timer = setTimeout(function () {
                // 取消ajax  请求
                xhr.abort();
            },timeout);
        }

    }
    /*
    * 把对象转换成字符串
    * */
    function getStrWithObj(paramsObj) {
        var arr = [];
        for(var k in paramsObj){
            var str = k + \'=\' + paramsObj[k];
            arr.push(str);
        }
        arr.push(\'random=\'+ getRandomStr());
        return arr.join(\'&\');
    }

    /*
    返回一个随机数
    * */
    function getRandomStr() {
        return Math.random() + (new Date().getTime())
    }

    window.AjaxTool = AjaxTool;
})(window);

index3.ejs:

<body>
<input id="account" type="text" name="account">
<input id="pwd" type="text" name="pwd">
<button id="send">发送一个请求</button>
<script>
    window.onload=function () {

        var btn = document.getElementById(\'send\');
        btn.onclick = function () {
            // 使用原生的ajax 技术,发送一个网络请求
            // 1.创建XMLHttpRequest对象
            var xhr;
            if(window.XMLHttpRequest){
                xhr = new XMLHttpRequest();
            }else {
                xhr = new ActiveXObject(\'Microsoft.XMLHTTP\');
            }

            // 从页面获取需要传递的数据
            var userName = document.getElementById(\'account\').value;
            var pwd = document.getElementById(\'pwd\').value;

            // 2.准备发送
            /*
             参数1: 请求方式 (get/post)
             参数2: 请求url
             参数3: 是否异步
          */
            // 后面跟一个随机数值,保证每次发送ajax请求,都是真的发然后从响应中获取最新数据,而不是从缓存中取得
            xhr.open(\'get\', \'http://localhost:3000/api/two?account=\' + account + \'&pwd=\' + pwd + \'&random=\' + getRandomStr(), true);

            // 3. 发送
            xhr.send();

            // 4. 监听服务器的响应
            // 一旦服务器响应回来之后, 就会执行这个函数
            xhr.onreadystatechange = function () {
                // 5. 处理响应的数据 (对方说话)
                console.log(xhr.readyState);
                if(xhr.readyState === 4){  // 代表服务器已经给了响应, 不代表响应成功
                    if(xhr.status === 200){
                        console.log(xhr.response);
                    }
                }
            }
        }
    }

    function getRandomStr() {
        return Math.random() + (new Date().getTime())
    }
</script>

</body>

3、简单版原生 post方式

<body>
<input id="account" type="text" name="account">
<input id="pwd" type="text" name="pwd">
<button id="send">发送一个请求</button>
<script>
    window.onload=function () {
        var btn = document.getElementById(\'send\');
        btn.onclick = function () {
            // 1. 获取数据
            var account = document.getElementById(\'account\').value;
            var pwd = document.getElementById(\'pwd\').value;


            // 第一步
            var xhr = new XMLHttpRequest();
            // 第二步
            xhr.open(\'post\',\'http://localhost:3000/api/four\',true)
            // 第三步
            xhr.setRequestHeader(\'Content-Type\',\'application/x-www-form-urlencoded\');
            xhr.send(\'account=\'+account + \'&pwd=\' + pwd);

            // 第四步
            xhr.onreadystatechange = function () {
                console.log(xhr.readyState);
                console.log(xhr.status);
                if(xhr.readyState === 4 && xhr.status === 200){
                    console.log(xhr.responseText);
                }else {
                    console.log(\'请求失败\');
                }
            }

        }
    }

</script>

</body>

4、ajax 完整封装

(function(window){
    function AjaxTool(){}
    AjaxTool.ajaxRequest = function(params,successCallBack,errorCallBack){
        // 0. 获取参数
        var requestType = params[\'requestType\'] || \'get\';
        var url = params[\'url\'];
        var paramsObj = params[\'paramsObj\'];
        var timeout = params[\'timeout\'];
        console.log(params);
        // 1.创建XMLHttpRequest对象 (找到一个电话)
        var xhr;
        if(window.XMLHttpRequest){
            xhr =new XMLHttpRequest();
        }else{
            xhr = new ActiveXObject(\'Microsoft.XMLHTTP\');
        }

        // 2.判断请求方式
        if(requestType.toLowerCase() === \'get\'){
            var codeURI = encodeURI(url + \'?\' + getStrWithObject(paramsObj));
            xhr.open(\'get\',codeURI,true);
            xhr.send();
        }else if(requestType.toLowerCase() === \'post\'){
            // 请求体
            var codeParam = encodeURI(getStrWithObject(paramsObj));
            xhr.open(\'post\',url,true);
            xhr.setRequestHeader(\'Content-Type\',\'application/x-www-form-urlencoded\');
            console.log(codeParam);
            xhr.send(codeParam);

        }

        // 3. 监听服务器响应
        xhr.onreadystatechange = function(){
            // 3.1 处理响应数据
            if(xhr.readyState === 4){
                // 4 代表服务器给响应了,并不代表响应成功
                if(xhr.status === 200){
                    successCallBack(xhr);
                    // 清除定时器
                    clearTimeout(timer);
                }else{
                    errorCallBack();
                }
            }
        }


        // 4. 控制响应时间
        var timer;
        if(timeout > 0){
            timer = setTimeout(function(){
                // 取消ajax请求
                xhr.abort();
            },timeout);
        }


    }



    /*
    返回一个随机数
    */
    function getRandomStr(){
        return	Math.random() + (new Date().getTime());
    }


    /*
    把对象转成字符串
    */
    function getStrWithObject(paramsObj){
        var arr = [];
        for(var key in paramsObj){
            var str = key + \'=\' + paramsObj[key];
            arr.push(str)
        }
        arr.push(\'random=\' + getRandomStr())
        return arr.join(\'&\');
    }
    window.AjaxTool = AjaxTool;
})(window)

index5.ejs:

<body>
<input id="account" type="text" name="account">
<input id="pwd" type="text" name="pwd">
<button id="send">发送一个请求</button>
<script src="../js/AjaxTool.js"></script>
<script>
    window.onload=function () {
        var btn = document.getElementById(\'send\');
        btn.onclick = function () {
            // 1. 获取数据
            var account = document.getElementById(\'account\').value;
            var pwd = document.getElementById(\'pwd\').value;

            // 2. 处理数据
            var paramsObj = {
                \'account\':account,
                \'pwd\':pwd
            }

            var params = {
                \'requestType\':\'post\',
                \'url\':\'http://localhost:3000/api/five\',
                \'paramsObj\':paramsObj,
                \'timeout\':2000
            }

            AjaxTool.ajaxRequest(params,function (xhr) {
                console.log(\'成功\' + xhr.responseText);
            },function () {
                console.log(\'失败\');
            });

        }
    }

</script>

</body>

index.js 服务端路由文件:

router.get(\'/five\',(req,res,next)=>{
    res.render(\'index5\')
});

router.post(\'/api/five\',(req,res,next)=>{
    console.log(req.body);
    res.json({
        status:200,
        result:\'this is five...method:post..\'
    })
});

访问:http://localhost:3000/five

输入admin 123456 ,然后提交

前端打印:成功{"status":200,"result":"this is five...method:post.."}

服务端打印:{ account: \'admin\', pwd: \'123123\', random: \'1547522571613.208\' }

5、用 jquery 进行 ajax 请求

三方封装的是最完善的,我们用三方封装好的即可,但是对ajax原生的执行的大致逻辑知道一些比较好。

index6.ejs:

<body>
<form action="http://localhost:3000/api/six" method="post">
    <input id="account" type="text" name="account">
    <input id="pwd" type="text" name="pwd">
    <input id="send" type="submit" value="请求">
</form>
<script src="/js/jquery.js"></script>
<script>
    $(\'form\').on(\'submit\', function () {
        console.log($(this).serialize());  //account=admin&pwd=123456
        $.ajax({
            url: $(this).attr(\'action\'),
            type: $(this).attr(\'method\'),
            data: $(this).serialize(),
            success: function (data) {
                console.log(data);  //{status: 200, result: "this is six...."}
            }
        });

        // 阻止默认事件
        return false;
    });
</script>

服务端:

router.post(\'/api/six\',(req,res,next)=>{
    console.log(req.body);
    res.json({
        status:200,
        result:\'this is six....\'
    })
});

二、跨域

1、什么是跨域

同源策略:

2、解决方案:

jsonp
document.domain+iframe :只有主域名相同的情况下方可使用此方法
location.hash + iframe
window.name + iframe
window.postMessage 
flash等第三方插件

3、跨域演示

express-generator 快速创建一个应用的骨架server,然后在服务端index.js 路由中

router.get(\'/\', function(req, res, next) {
  // res.render(\'index\', { title: \'Express\' });
    console.log(`收到客户端的请求: ${req.url}`);
    res.end(\'end\');
});

在本地新创建一个页面,不要通过和 server 端口一致

<body>
<button id="send">点我</button>
<script src="js/AjaxTool.js"></script>
<script>
    window.onload = function () {
        var btn = document.getElementById(\'send\');
        btn.onclick = function () {
            var paramObj = {
                \'name\':\'zhangsan\',
                \'pwd\':\'123\'
            };
            var params = {
             \'requestType\' : \'get\',
             \'url\' : \'http://localhost:3000/\',
             \'paramObj\' : paramObj,
             timeout : 2000
            };

            // 发起请求
            AjaxTool.ajaxRequest(params,function (xhr) {
                console.log(\'success...\'+ xhr.responseText);
            },function () {
                console.log(\'failed.....\');
            })
        }
    }
</script>

</body>

结果:

服务端还是收到请求了,打印:

收到客户端的请求: /?name=zhangsan&pwd=123&random=1547690599507.3115
GET /?name=zhangsan&pwd=123&random=1547690599507.3115 - - ms - -

客户端打印如下图:

4、jsonp 解决跨域问题

  • jsonp跨域必须前后端联合支持

  • jsonp只支持get不支持post

(1) 演示1

路由:

router.get(\'/\',function (req,res,next) {
    console.log(`收到客户端的请求: ${req.url}`);
    var data = JSON.stringify({
        status_code:200,
        result:{
          name:\'张三\',
          age:19,
          friend:[\'李四\',\'王五\',\'赵六\']
        }
    });
    res.end(\'getData(\'+data+\')\');
});

前端页面:

<body>
<script>
    function getData(data) {
        console.log(data);
    }
</script>
<script src="http://localhost:3000/"></script>
</body>

通过 script 引入,来跨域请求,这个是可行的,同样的方式,还有 css标签的引入

1547692058626

(2) 封装

路由:

router.get(\'/\',function (req,res,next) {
    console.log(`收到客户端的请求: ${req.url}`);
    var data = JSON.stringify({
        status_code:200,
        result:{
          name:\'张三\',
          age:19,
          friend:[\'李四\',\'王五\',\'赵六\']
        }
    });
    console.log(`${req.query.callback}(${data})`);
    res.end(`${req.query.callback}(${data})`);
});

前端:

<body>
<script>

jsonp({
    url: \'http://localhost:3000/\',
    data: \'\',
    success: function (data) {
        console.log(11111);
        console.log(data);
    }
});
jsonp({
    url: \'http://localhost:3000/\',
    data: \'\',
    success: function (data) {
        console.log(22222);

        console.log(data);
    }
});

/*
* 1、让函数名称不一致
* 2、调用完成后删除
* */
function jsonp(option) {
    // 1. 将用户通过对象的命名空间传递进来的函数 挂载到全局
    var callbackName = \'hello_\' + Math.random().toString().substr(2);
    window[callbackName] = function (data) {
        option.success(data);
        // 删除 script 标签 ,多次调用后 script 太多了,在这里删除掉
        document.body.removeChild(script);
    };

    // 1. 处理url的拼接
    option.url = option.url + \'?callback=\' + callbackName;
    // 2. 创建script标签
    var script = document.createElement(\'script\');
    script.src = option.url;
    document.body.appendChild(script);


    /*说明: 拼接完url后,url 会带上函数的名称,服务端根据url 取得函数名称,然后返回的时候
        res.end(`${req.query.callback}(${data})`); 
    * */
}

</script>
</body>

前端代码注释:

加断点可以查看执行流程,首先 jsonp({})执行,接着到下面的 function jsonp({}),在下面的 function jsonp() 里面, window[callbackName] = function (data) {} ,在这里只是声明了函数,并且是全局的,但是并没有调用,里面的东西是在后来服务端 响应后调用的,并接着调用 了 里面的 option.success(data) 的函数,因为这个时候,服务端返回的时候把参数data 也传回来了 res.end(${req.query.callback}(${data})); 。所以接着执行了上面的 jsonp({}) 里面的 success:function(){data} 的函数。

执行结果:

三、nrm

什么是nrm:

install:

$ npm install -g nrm

查看有哪些源:

$ nrm ls

* npm -----  https://registry.npmjs.org/
  cnpm ----  http://r.cnpmjs.org/
  taobao --  https://registry.npm.taobao.org/
  nj ------  https://registry.nodejitsu.com/
  rednpm -- http://registry.mirror.cqupt.edu.cn
  skimdb -- https://skimdb.npmjs.com/registry

选择镜像源:

$ nrm use cnpm  //switch registry to cnpm

    Registry has been set to: http://r.cnpmjs.org/

注意:每次安装包的时候,依然是使用 npm 命令来安装。

以上是关于ajax的主要内容,如果未能解决你的问题,请参考以下文章

Javascript代码片段在drupal中不起作用

前端面试题之手写promise

Ajax 片段元标记 - Googlebot 未读取页面内容

执行AJAX返回HTML片段中的JavaScript脚本

javascript AJAX片段

Spring MVC 3.2 Thymeleaf Ajax 片段