Ajax篇


同步和异步

概念

  • 同步:必须等待前面的任务完成,才能继续后面的任务。

  • 异步:不受当前任务的影响。

异步更新网站

我们在访问一个普通的网站时,当浏览器加载完HTML、CSS、JS以后,网站的内容就固定了。如果想让网站内容发生更改,就必须刷新页面才能够看到更新的内容。

可如果用到异步更新,情况就大为改观了。比如,我们在访问新浪微博时,看到一大半了,点击底部的加载更多,会自动帮我们加载更多的微博,同时页面并没有刷新

试想一下,如果没有异步刷新的话,每次点击“加载更多”,网页都要刷新,体验就太不好了。

web前端里的异步更新,就要用到 Ajax

Ajax

概念

AjaxAsynchronous Javascript And XML:异步 JavaScriptXML)。它是对于现有技术的结合。Ajax的核心是 js对象XMLHttpRequest。也就是使用 XMLHttpRequest对象与服务器通信。 它可以使用 JSON,XML,HTMLtext 文本等格式发送和接收数据。

在浏览器中,我们可以在不刷新页面的情况下,通过ajax的方式与服务器通信,交换数据,或更新页面,去获取一些新的内容。

XMLHttpRequest对象详解

创建异步对象

var xhr;
if (window.XMLHttpRequest) {
    // Mozilla, Safari, IE7+ ...
  hr = new XMLHttpRequest();
} else if (window.ActiveXObject) {
  // IE 6 and older
  xhr = new ActiveXObject("Microsoft.XMLHTTP");
}

发送请求

发送请求的方法:

// method:请求的类型;GET 或 POST;url:文件在服务器上的位置;async:true(异步)或 false(同步)
open(method, url, async);

GET请求

xhr.open('get', '请求的url');
xhr.send();

POST请求

如果想让 像form 表单提交数据那样使用POST请求,就需要使用 XMLHttpRequest对象的 setRequestHeader()方法 来添加 HTTP头。然后在 send() 方法中添加想要发送的数据:

xhr.open('post', '请求的url', true);
xhr.setRequestHeader('Content-type', 'application/x-wwww-form-urlencoded');
xhr.send('name=tom&age=18');

onreadystatechange 事件

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

xhr.onreadystatechange = function () {
  // Process the server response here.
};
readyState状态
  • 0: 请求未初始化

  • 1: 服务器连接已建立

  • 2: 请求已接收

  • 3: 请求处理中

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

status状态
  • 200: “OK”。

  • 404: 未找到页面。

onreadystatechange 事件中,readyState 等于 4,且状态码为200时,表示响应已就绪

服务器响应的内容

  • responseText:获得字符串形式的响应数据。

  • responseXML:获得 XML 形式的响应数据。

如果响应的是普通字符串,就使用responseText;如果响应的是XML,使用responseXML

发送 Ajax 请求的五个步骤

(1)创建异步对象。即 XMLHttpRequest对象。

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

(3)发送请求。

(4)注册事件。 注册onreadystatechange事件,状态改变时就会调用。如果要在数据完整请求回来的时候才调用,我们需要手动写一些判断的逻辑。

(5)获取返回的数据。

Ajax 请求实例

GET请求示例
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Ajax的get请求</title>
</head>

<body>
    <h1>发送get请求</h1>
    <input type="button" value="发送get请求" id="getAjax">

    <script type="text/javascript">
        document.querySelector("getAjax").onclick = function() {
            // 发送ajax请求
            var xhr = new XMLHttpRequest();
            xhr.open('get', '请求的url');
            xhr.send();
            xhr.onreadystatechange = function() {
                if (xhr.readyState == 4 && xhr.status == 200) {
                    console('数据返回成功');
                    console.log(xhr.responseText);
                    document.querySelector('h1').innerHTML = xhr.responseText;
                }
            }
        }
    </script>
</body>

</html>
POST请求示例
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Ajax的Post请求</title>
</head>

<body>
    <h1>发送post请求</h1>
    <input type="button" value="发送Post请求" id="postAjax">

    <script type="text/javascript">
        var xhr = new XMLHttpRequest();
        xhr.open('post', '请求的url');
        // 如果想要使用post提交数据,必须添加此行
        xhr.setRequestHeader('Content-type', 'application/x-wwww-form-urlencoded');
        // 将数据通过send方法传递
        xhr.send('name=tom&age=18');
        xhr.onreadystatechange = function() {
            if (xhr.readyState == 4 && xhr.status == 200) {
                console.log(xhr.responseText);
            }
        }
    </script>
</body>

</html>

Ajax 传输 JSON

JSON的语法

JSON(JavaScript Object Notation):是ECMAScript的子集。作用是进行数据的交换。语法更为简洁,网络传输、机器解析都更为迅速。

语法规则:
  • 数据在键值对中

  • 数据由逗号分隔

  • 花括号保存对象

  • 方括号保存数组

数据类型:
  • 数字(整数或浮点数)

  • 字符串(在双引号中)

  • 逻辑值(true 或 false)

  • 数组(在方括号中)

  • 对象(在花括号中)

  • null

示例:

// 对象
{
  "name":"fox",
  "age":"18",
  "sex":"true",
  "car":null
}

// 数组
[
  {
      "name":"小小胡",
      "age":"1"
  },
  {
      "name":"小二胡",
      "age":"2"
  }
]

json 字符串 与 js 对象转换

基本所有的语言都有将 json 字符串转化为该语言对象的语法。

JS中的转换

JSON.parse():将JSON字符串转化为 js 对象。例如:

var jsObj = JSON.parse(ajax.responseText);

JSON.stringify():将 JS 对象转化为JSON字符串。例如:

var Obj = {
      name: "tom",
      age: 18,
    };
    // 将 js 对象格式化为 JSON 字符串
    var jsonStr = JSON.stringify(Obj);
PHP中的转换
  • json_decode()方法:将json字符串转化为变量。

  • json_encode()方法:将变量转化为json字符串。

jQuery中的 Ajax

JQuery作为最受欢迎的JS框架之一,常见的Ajax已经帮助我们封装好了,只需要调用即可。更为详细的api文档可以查阅:w3cSchool_JQueryAjax

格式:

$.ajax({
            url: '请求地址',
            data: 'name=tom&age=16',
            type: 'POST',
            // 请求成功执行的方法
            success: function(argument) {},
            // 在发送请求之前调用,可以做一些验证之类的处理
            beforeSend: function(argument) {}, 
            // 请求失败调用
            error: function(argument) {},
        })
  • ajax 会自动带上同源的 cookie,不会带上不同源的 cookie
  • 可以通过前端设置 withCredentials 为 true, 后端设置 Header 的方式让 ajax 自动带上不同源的 cookie,但是这个属性对同源请求没有任何影响。会被自动忽略。

withCredentials | MDN

var xhr = new XMLHttpRequest();
xhr.open("GET", "http://example.com/", true);
xhr.withCredentials = true;
xhr.send(null);

Ajax函数封装

此部分把ajax发送HTTP的常用请求进行封装,方便调用,减少代码冗余,解耦合,在编写项目时可以作为工具类使用。

请求封装

// get请求封装
        function getAjax(url, data) {
            var xhr = new XMLHttpRequest();
            if (data) {
                url += '?';
                url += data;
            } else {}
            xhr.open('get', url);
            xhr.send();
            xhr.onreadystatechange = function() {
                if (xhr.readyState == 4 && ajax.status == 200) {
                    console.log(ajax.responseText);
                }
            }
        }

        // post请求封装
        function postAjax(url, data) {
            var xhr = new XMLHttpRequest();
            xhr.open('post', url);
            xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
            if (data) {
                xhr.send(data);
            } else {
                xhr.send();
            }
            xhr.onreadystatechange = function() {
                if (xhr.readyState == 4 && xhr.status == 200) {
                    console.log(xhr.responseText);
                }
            }
        }

        // get和post一起封装
        /*
            参数1:url
            参数2:数据
            参数3:请求的方法
            参数4:数据成功获取以后,调用的方法
        */
        function ajaxTool(url, data, method, success) {
            var xhr = new XMLHttpRequest();
            // 如果忽略大小写呢
            if (method == 'get') {
                if (data) {
                    url += '?';
                    url += data;
                } else {}
                xhr.open(method, url);
                xhr.send();
            } else {
                xhr.open(method, url);
                xhr.setRequestHeader('Content-type', 'application-x-www-form-urlencoded');
                if (data) {
                    xhr.send(data);
                } else {
                    xhr.send();
                }
            }

            xhr.onreadystatechange = function() {
                if (xhr.readyState == 4 && xhr.status == 200) {
                    console.log(xhr.responseText);
                    success(xhr.responseText);
                }
            }

        }

函数调用

// get请求
var resData = ajaxTool('url', 'data', 'get', function(data) {
            console.log(data);
        })
        console.log(resData);
// post请求
var resData = ajaxTool('url', 'data', 'post', function(data) {
            console.log(data);
        })
        console.log(resData);

同源和跨域

同源

同源策略是浏览器的一种安全策略,所谓同源是指域名,协议,端口完全相同

跨域

从我们自己的网站访问别人网站的内容,就叫跨域。

跨域

出于安全性考虑,浏览器不允许ajax跨域获取数据。

  • iframe:出于安全性考虑,浏览器的开发厂商已经禁止了这种方式。

  • JSONPscript标签的 src属性传递数据。

JSONP

JSONP(JSON with Padding):带补丁的 json,本质是利用了 <script src=""></script>标签具有可跨域的特性,由服务端返回一个预先定义好的JS函数的调用,并且将服务器数据以该函数参数的形式传递过来。此方法需要前后端配合完成。

html标签的 src 属性是支持跨域的:

    <img src="http://xxx.com/xxx.jpg" alt="">

jsonp就是利用这个特性实现的跨域,但用的是 script 标签。如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<body>

<!-- jsonp 就是 利用 src,实现的跨域 用的是 script标签 -->
<script type="text/javascript"  src='http://192.168.141.137/2018-02-28/myData.php'></script>
</body>
</html>

上述代码的意思是:刷新A服务器上的index页面后,会去请求 B 服务器上的 myData.php 这个页面。而且请求的方式是get 请求。但是 B 服务器上的页面不是你想请求就可以请求的,大家一起配合才可以。

具体实现步骤:

需要首先声明的是,jsonp只能通过 GET 方式进行请求

(1)A客户端的代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<body>

</body>
</html>
<script type="text/javascript">

    // 定义 fn() 方法
    function fn(data) {
        console.log('我被调用了哦');
        console.log(data);
    }
</script>

<!-- 使用 script标签 发送了 get请求 去到了一个 php页面 -->
<script type="text/javascript" src='http://192.168.141.137/01.php?callback1=fn'></script>

我们来分析上方代码中的最后一行的那个url:A 客户端请求的是 B服务器上的 01.php页面。url里有个callback1=fn,意思是:callback1是A和B 之间的约定,约定后,将执行方法 fn。

其实,fn方法已经在最后一行代码中执行了。只不过,fn方法里的data数据,是从 B 服务器中获取的。

(2)B服务器端的代码:

<?php
    $mycallBack = $_GET['callback1'];

    $arr = array("zhangsan","lisi","zhaoliu");

    echo $mycallBack.`(`.json_encode($arr).`)`;    //字符串拼接
?>

代码解释:

第一行的callback1 是A和B之间的约定,二者必须一致。

echo语句中输出的内容,即使要返回给A客户端的内容,此内容会保存在 A 客户端的fn方法的data里。 data[0]指的是 zhangsan。

json_encode指的是,将php对象转化为 json。

刷新A页面,输出结果为:

    mycallBack(["zhangsan","lisi","zhaoliu"])

jQuery 中的 JSONP

jQuery 中发送 Ajax 请求,格式是:

        $("#btn").click(function(){
            $.ajax({
                url:"./data.php?callback1=fn",
                dataType:"jsonp",
                type:"get",
                //jsonp:"callback1",   //传递给B服务器的回调函数的名字(默认为 callback)
                //jsonCallBack:"fn"    //自定义的函数名称。默认为 jQuery 自动生成的随机函数名
                success:function(data){
                    alert(data);
                    //$("#showInfo").html(data);
                },
                error:function(e){
                    console.log(e);
                }
            });
        });

那如果数据是 JSONP,上方代码则改为:

        $("#btn").click(function(){
            $.ajax({
                url:"./data.php?fn",
                dataType:"text",
                type:"get",
                success:function(data){
                    alert(data);
                    //$("#showInfo").html(data);
                },
                error:function(e){
                    console.log(e);
                }
            });
        });

评论
评论
  目录