Ajax

139 阅读11分钟

1.HTTP

HTTP(hypertext transport protocol)协议『超文本传输协议』,协议详细规定了浏览器和万维网服务器之间互相通信的规则。 约定, 规则

请求报文

重点是格式与参数

行      POST  /s?ie=utf-8  HTTP/1.1 
头      Host: atguigu.com
        Cookie: name=guigu
        Content-type: application/x-www-form-urlencoded
        User-Agent: chrome 83
空行
体      username=admin&password=admin

响应报文

行      HTTP/1.1  200  OK
头      Content-Type: text/html;charset=utf-8
        Content-length: 2048
        Content-encoding: gzip
空行    
体      <html>
            <head>
            </head>
            <body>
                <h1>尚硅谷</h1>
            </body>
        </html>
        
* 404
* 403
* 401
* 500
* 200

2.-express框架

//1. 引入express
const express = require('express');

//2. 创建应用对象
const app = express();

//3. 创建路由规则
// request 是对请求报文的封装
// response 是对响应报文的封装
app.get('/', (request, response)=>{
    //设置响应
    response.send('HELLO EXPRESS');
});

//4. 监听端口启动服务
app.listen(8000, ()=>{
    console.log("服务已经启动, 8000 端口监听中....");
});

启动:
node 文件名.js  //http://127.0.0.1:8000/

3.原生 AJAX

3.1 AJAX 简介

AJAX 全称为 Asynchronous JavaScript And XML,就是异步的 JS 和 XML。 
通过 AJAX 可以在浏览器中向服务器发送异步请求,最大的优势:无刷新获取数据。 
AJAX 不是新的编程语言,而是一种将现有的标准组合在一起使用的新方式。 

3.2 XML 简介

XML 可扩展标记语言。 
XML 被设计用来传输和存储数据。
XML 和 HTML 类似,不同的是 HTML 中都是预定义标签,而 XML 中没有预定义标签, 
全都是自定义标签,用来表示一些数据。 
比如说我有一个学生数据: 
name = "孙悟空" ; age = 18 ; gender = "男" ; 
用 XML 表示: 
<student> 

<name>孙悟空</name> 

<age>18</age> 

<gender></gender> 

</student> 
现在已经被 JSON 取代了。 

用 JSON 表示: 

{"name":"孙悟空","age":18,"gender":"男"} 

3.3 AJAX 的特点

3.3.1 AJAX 的优点

1) 可以无需刷新页面而与服务器端进行通信。 
2) 允许你根据用户事件来更新部分页面内容。 

3.3.2 AJAX 的缺点

1) 没有浏览历史,不能回退 
2) 存在跨域问题(同源) 
3) SEO 不友好 

3.4 AJAX 的使用

3.4.1 核心对象

XMLHttpRequest,AJAX 的所有操作都是通过该对象进行的。 

3.4.2 使用步骤

1) 创建 XMLHttpRequest 对象 

var xhr = new XMLHttpRequest(); 

2) 设置请求信息 

xhr.open(method, url); 

//可以设置请求头,一般不设置 

xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); 

3) 发送请求 

xhr.send(body) //get 请求不传 body 参数,只有 post 请求使用 

4) 接收响应 

//xhr.responseXML 接收 xml 格式的响应数据 

//xhr.responseText 接收文本格式的响应数据 

xhr.onreadystatechange = function (){ 

    if(xhr.readyState == 4 && xhr.status == 200){ 

        var text = xhr.responseText; 

        console.log(text); 

    } 

} 

3.4.3 GET

WAMP

<!--
    1.可以通过form标签的method属性指定发送请求的类型
    2.如果是get请求会将提交的数据拼接到URL后面
    ?userName=lnj&userPwd=123456
    3.如果是post请求会将提交的数据放到请求头中

    4.GET请求和POST请求的异同
    4.1相同点:
        都是将数据提交到远程服务器
    4.2不同点:
        4.2.1提交数据存储的位置不同
            GET请求会将数据放到URL后面
            POST请求会将数据放到请求头中
        4.2.2提交数据大小限制不同
            GET请求对数据有大小限制
            POST请求对数据没有大小限制

    5.GET/POST请求应用场景
        GET请求用于提交非敏感数据和小数据
        POST请求用于提交敏感数据和大数据
-->
<form action="02-get-post.php" method="post">
    <input type="text" name="userName"><br>
    <input type="password" name="userPwd"><br>
    <input type="submit" value="提交"><br>
</form>

//php
<?php
print_r($_GET);
echo $_GET["userName"];
echo $_GET["userPwd"];

print_r($_POST);
echo $_POST["userName"];
echo $_POST["userPwd"];
?>

express

		//获取button元素
        const btn = document.getElementsByTagName('button')[0];
        const result = document.getElementById("result");
        //绑定事件
        btn.onclick = function(){
            //1. 创建异步对象
            const xhr = new XMLHttpRequest();
            //2. 初始化 设置请求方法和 url(传参)
                /*
                method:请求的类型;GET 或 POST
                url:文件在服务器上的位置
                async:true(异步)或 false(同步)
                */
            xhr.open('GET', 'http://127.0.0.1:8000/server?a=100&b=200&c=300');
            //xhr.open("GET","05-ajax-get.txt?t="+(new Date().getTime()),true);
            //3. 发送
            xhr.send();
            //4. 事件绑定 处理服务端返回的结果
            // on  when 当....时候
            // readystate 是 xhr 对象中的属性, 表示状态 0 1 2 3 4
            /*
                    0: 请求未初始化
                    1: 服务器连接已建立
                    2: 请求已接收
                    3: 请求处理中
                    4: 请求已完成,且响应已就绪
            */
            // change  改变
            xhr.onreadystatechange = function(){
                //判断 (服务端返回了所有的结果)
                if(xhr.readyState === 4){
                    //判断响应状态码 200  404  403 401 500
                    // 2xx 成功
                    if(xhr.status >= 200 && xhr.status < 300||
                           xmlhttp.status === 304){
                        //处理结果  行 头 空行 体
                        //响应 
                        // console.log(xhr.status);//状态码
                        // console.log(xhr.statusText);//状态字符串
                        // console.log(xhr.getAllResponseHeaders());//所有响应头
                        // console.log(xhr.response);//响应体
                        //设置 result 的文本
                        result.innerHTML = xhr.response;
                        alert(xhr.responseText);
                    }else{
                        console.log("没有接收到服务器返回的数据");
                    }
                }
            }
        }
服务端//http://127.0.0.1:8000/server

const express = require('express');
const app = express();
app.get('/server', (request, response) => {
    //设置响应头  设置允许跨域
    response.setHeader('Access-Control-Allow-Origin', '*');
    //设置响应体
    response.send('HELLO AJAX - 2');
});
app.listen(8000, ()=>{
    console.log("服务已经启动, 8000 端口监听中....");
});

3.4.4 POST

        //获取元素对象
        const result = document.getElementById("result");
        //绑定事件
        result.addEventListener("mouseover", function(){
            //1. 创建对象
            const xhr = new XMLHttpRequest();
            //2. 初始化 设置类型与 URL
            xhr.open('POST', 'http://127.0.0.1:8000/server');
            //设置请求头(头名字,头值)
            xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded');
            xhr.setRequestHeader('name','atguigu');
            //3. 发送
            xhr.send('a=100&b=200&c=300');
            // xhr.send('a:100&b:200&c:300');
            // xhr.send('1233211234567');
            
            //4. 事件绑定
            xhr.onreadystatechange = function(){
                //判断
                if(xhr.readyState === 4){
                    if(xhr.status >= 200 && xhr.status < 300){
                        //处理服务端返回的结果
                        result.innerHTML = xhr.response;
                    }
                }
            }
        });

服务

//可以接收任意类型的请求 
app.all('/server', (request, response) => {
    //设置响应头  设置允许跨域
    response.setHeader('Access-Control-Allow-Origin', '*');
    //响应头 允许自定义
    response.setHeader('Access-Control-Allow-Headers', '*');
    //设置响应体
    response.send('HELLO AJAX POST');
});

POST上传文件

<!--
注意:
    1.上传文件一般使用POST提交
    2.上传文件必须设置enctype="multipart/form-data"
    3.上传的文件在PHP中可以通过$_FILES获取
    4.PHP中文件默认会上传到一个临时目录, 接收完毕之后会自动删除
-->
<!--
默认情况下服务器对上传文件的大小是有限制的, 如果想修改上传文件的限制可以修改php.ini文件
    file_uploads = On                 ; 是否允许上传文件 On/Off 默认是On
    upload_max_filesize = 2048M       ; 上传文件的最大限制
    post_max_size = 2048M             ; 通过Post提交的最多数据

    max_execution_time = 30000      ; 脚本最长的执行时间 单位为秒
    max_input_time = 30000          ; 接收提交的数据的时间限制 单位为秒
    memory_limit = 2048M            ; 最大的内存消耗
-->
//html
<form action="03-post-file.php" method="post" enctype="multipart/form-data">
    <input type="file" name="upFile"><br>
    <input type="submit" value="上传"><br>
</form>

//php
<?php
//echo "post page";
//print_r($_POST);
//echo "<br>";
//print_r($_FILES);

// 1.获取上传文件对应的字典
$fileInfo = $_FILES["upFile"];
//print_r($fileInfo);
// 2.获取上传文件的名称
$fileName = $fileInfo["name"];
// 3.获取上传文件保存的临时路径
$filePath = $fileInfo["tmp_name"];

//echo $fileName;
//echo "<br>";
//echo $filePath;

// 4.移动文件
move_uploaded_file($filePath, "./source/".$fileName);
?>

3.4.5 JSON

        const result = document.getElementById('result');
        //绑定键盘按下事件
        window.onkeydown = function(){
            //发送请求
            const xhr = new XMLHttpRequest();
            //设置响应体数据的类型
            xhr.responseType = 'json';
            //初始化
            xhr.open('GET','http://127.0.0.1:8000/json-server');
            //发送
            xhr.send();
            //事件绑定
            xhr.onreadystatechange = function(){
                if(xhr.readyState === 4){
                    if(xhr.status >= 200 && xhr.status < 300){
                        //
                        // console.log(xhr.response);
                        // result.innerHTML = xhr.response;
                        // 1. 手动对数据转化
                        // let data = JSON.parse(xhr.response);
                        // console.log(data);       //{name:atguigu}
                        // result.innerHTML = data.name;
                        // 2. 自动转换
                        console.log(xhr.response);
                        result.innerHTML = xhr.response.name;
                    }
                }
            }
        }

服务端

//JSON 响应
app.all('/json-server', (request, response) => {
    //设置响应头  设置允许跨域
    response.setHeader('Access-Control-Allow-Origin', '*');
    //响应头
    response.setHeader('Access-Control-Allow-Headers', '*');
    //响应一个数据
    const data = {
        name: 'atguigu'
    };
    //对对象进行字符串转换
    let str = JSON.stringify(data);
    //设置响应体
    response.send(str);
});

3.4.6 解决 IE 缓存问题

问题:在一些浏览器中(IE),由于缓存机制的存在,ajax 只会发送的第一次请求,剩余多次请求不会在发送给浏览器而是直接加载缓存中的数据。 

解决方式:浏览器的缓存是根据 url 地址来记录的,所以我们只需要修改 url 地址即可避免缓存问题 

xhr.open("get","/testAJAX?t="+Date.now()); 

服务器

app.get('/ie', (request, response) => {
    //设置响应头  设置允许跨域
    response.setHeader('Access-Control-Allow-Origin', '*');
    //设置响应体
    response.send('HELLO IE - 5');
});

3.4.7 超时与网络异常

        const btn = document.getElementsByTagName('button')[0];
        const result = document.querySelector('#result');

        btn.addEventListener('click', function(){
            const xhr = new XMLHttpRequest();
            //超时设置 2s 设置
            xhr.timeout = 2000;
            //超时回调
            xhr.ontimeout = function(){
                alert("网络异常, 请稍后重试!!");
            }
            //网络异常回调
            xhr.onerror = function(){
                alert("你的网络似乎出了一些问题!");
            }

            xhr.open("GET",'http://127.0.0.1:8000/delay');
            xhr.send();
            xhr.onreadystatechange = function(){
                if(xhr.readyState === 4){
                    if(xhr.status >= 200 && xhr.status< 300){
                        result.innerHTML = xhr.response;
                    }
                }
            }
        })

服务器

//延时响应
app.all('/delay', (request, response) => {
    //设置响应头  设置允许跨域
    response.setHeader('Access-Control-Allow-Origin', '*');
    response.setHeader('Access-Control-Allow-Headers', '*');
    setTimeout(() => {
        //设置响应体
        response.send('延时响应');
    }, 1000)
});

3.4.8 取消请求

        //获取元素对象
        const btns = document.querySelectorAll('button');
        let x = null;

        btns[0].onclick = function(){
            x = new XMLHttpRequest();
            x.open("GET",'http://127.0.0.1:8000/delay');
            x.send();
        }

        // abort 取消
        btns[1].onclick = function(){
            x.abort();
        }

3.4.9 重复请求问题

        //获取元素对象
        const btns = document.querySelectorAll('button');
        let x = null;
        //标识变量
        let isSending = false; // 是否正在发送AJAX请求

        btns[0].onclick = function(){
            //判断标识变量
            if(isSending) x.abort();// 如果正在发送, 则取消该请求, 创建一个新的请求
            x = new XMLHttpRequest();
            //修改 标识变量的值
            isSending = true;
            x.open("GET",'http://127.0.0.1:8000/delay');
            x.send();
            x.onreadystatechange = function(){
                if(x.readyState === 4){
                    //修改标识变量
                    isSending = false;
                }
            }
        }

        // abort
        btns[1].onclick = function(){
            x.abort();
        }

3.4.10 AJAX 请求状态

xhr.readyState 可以用来查看请求当前的状态 

https://developer.mozilla.org/zh-CN/docs/Web/API/XMLHttpRequest/readyState 

0: 表示 XMLHttpRequest 实例已经生成,但是 open()方法还没有被调用。 

1: 表示 send()方法还没有被调用,仍然可以使用 setRequestHeader(),设定 HTTP请求的头信息。 

2: 表示 send()方法已经执行,并且头信息和状态码已经收到。 

3: 表示正在接收服务器传来的 body 部分的数据。 

4: 表示服务器数据已经完全接收,或者本次接收已经失败了 

3.4.11AJAX封装

function obj2str(obj) {
    /*
    {
        "userName":"lnj",
        "userPwd":"123456",
        "t":"3712i9471329876498132"
    }
    */
    obj = obj || {}; // 如果没有传参, 为了添加随机因子,必须自己创建一个对象
    obj.t = new Date().getTime();
    var res = [];
    for(var key in obj){
        // 在URL中是不可以出现中文的, 如果出现了中文需要转码
        // 可以调用encodeURIComponent方法
        // URL中只可以出现字母/数字/下划线/ASCII码
        res.push(encodeURIComponent(key)+"="+encodeURIComponent(obj[key])); // [userName=lnj, userPwd=123456];
    }
    return res.join("&"); // userName=lnj&userPwd=123456
}
function ajax(url, obj, timeout, success, error) {
    // 0.将对象转换为字符串
    var str = obj2str(obj); // key=value&key=value;
    // 1.创建一个异步对象
    var xmlhttp, timer;
    if (window.XMLHttpRequest)
    {// code for IE7+, Firefox, Chrome, Opera, Safari
        xmlhttp=new XMLHttpRequest();
    }
    else
    {// code for IE6, IE5
        xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
    }
    // 2.设置请求方式和请求地址
    /*
    method:请求的类型;GET 或 POST
    url:文件在服务器上的位置
    async:true(异步)或 false(同步)
    */
    xmlhttp.open("GET", url+"?"+str, true);
    // 3.发送请求
    xmlhttp.send();
    // 4.监听状态的变化
    xmlhttp.onreadystatechange = function (ev2) {
        /*
        0: 请求未初始化
        1: 服务器连接已建立
        2: 请求已接收
        3: 请求处理中
        4: 请求已完成,且响应已就绪
        */
        if(xmlhttp.readyState === 4){
            clearInterval(timer);
            // 判断是否请求成功
            if(xmlhttp.status >= 200 && xmlhttp.status < 300 ||
                xmlhttp.status === 304){
                // 5.处理返回的结果
                // console.log("接收到服务器返回的数据");
                success(xmlhttp);
            }else{
                // console.log("没有接收到服务器返回的数据");
                error(xmlhttp);
            }
        }
    }
    // 判断外界是否传入了超时时间
    if(timeout){
        timer = setInterval(function () {
            console.log("中断请求");
            xmlhttp.abort();
            clearInterval(timer);
        }, timeout);
    }
}

调用

		ajax("04-ajax-get.php", {
                    "userName":"lnj",
                    "userPwd":"123456"
                }, 3000
                , function (xhr) {
                    alert(xhr.responseText);
                }, function (xhr) {
                    alert("请求失败");
                });

传入对象

function obj2str(data) {
    /*
    {
        "userName":"lnj",
        "userPwd":"123456",
        "t":"3712i9471329876498132"
    }
    */
    data = data || {}; // 如果没有传参, 为了添加随机因子,必须自己创建一个对象
    data.t = new Date().getTime();
    var res = [];
    for(var key in data){
        // 在URL中是不可以出现中文的, 如果出现了中文需要转码
        // 可以调用encodeURIComponent方法
        // URL中只可以出现字母/数字/下划线/ASCII码
        res.push(encodeURIComponent(key)+"="+encodeURIComponent(data[key])); // [userName=lnj, userPwd=123456];
    }
    return res.join("&"); // userName=lnj&userPwd=123456
}

function ajax(option) {
    // 0.将对象转换为字符串
    var str = obj2str(option.data); // key=value&key=value;
    // 1.创建一个异步对象
    var xmlhttp, timer;
    if (window.XMLHttpRequest)
    {// code for IE7+, Firefox, Chrome, Opera, Safari
        xmlhttp=new XMLHttpRequest();
    }
    else
    {// code for IE6, IE5
        xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
    }
    // 2.设置请求方式和请求地址
    /*
    method:请求的类型;GET 或 POST
    url:文件在服务器上的位置
    async:true(异步)或 false(同步)
    */
    if(option.type.toLowerCase() === "get"){
        xmlhttp.open(option.type, option.url+"?"+str, true);
        // 3.发送请求
        xmlhttp.send();
    }else{
        xmlhttp.open(option.type, option.url,true);
        // 注意点: 以下代码必须放到open和send之间
        xmlhttp.setRequestHeader("Content-type","application/x-www-form-urlencoded");
        xmlhttp.send(str);
    }

    // 4.监听状态的变化
    xmlhttp.onreadystatechange = function (ev2) {
        /*
        0: 请求未初始化
        1: 服务器连接已建立
        2: 请求已接收
        3: 请求处理中
        4: 请求已完成,且响应已就绪
        */
        if(xmlhttp.readyState === 4){
            clearInterval(timer);
            // 判断是否请求成功
            if(xmlhttp.status >= 200 && xmlhttp.status < 300 ||
                xmlhttp.status === 304){
                // 5.处理返回的结果
                // console.log("接收到服务器返回的数据");
                option.success(xmlhttp);
            }else{
                // console.log("没有接收到服务器返回的数据");
                option.error(xmlhttp);
            }
        }
    }
    // 判断外界是否传入了超时时间
    if(option.timeout){
        timer = setInterval(function () {
            console.log("中断请求");
            xmlhttp.abort();
            clearInterval(timer);
        }, option.timeout);
    }

调用

ajax("POST", "08-ajax-post.php",{
                    "userName":"lnj",
                    "userPwd":"321"
                }, 3000, function (xhr) {
                    alert(xhr.responseText);
                }, function (xhr) {
                    alert("请求失败");
                });

练习(XML PHP JSON)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>10-ajax-test</title>
    <style>
        *{
            margin: 0;
            padding: 0;
        }
        div{
            width: 300px;
            height: 300px;
            border: 1px solid #000;
            margin: 50px auto;
            text-align: center;
            background: #ccc;
        }
        img{
            width: 200px;
            height: 200px;
            display: block;
            margin: 10px auto 10px;
            border: 1px solid #000;
        }
        p{
            text-align: center;
            background: pink;
        }
    </style>
    <script src="myAjax2.js"></script>
    <script>
        window.onload = function (ev) {
            // 1.获取需要设置的元素
            var oTitle = document.querySelector("#title");
            var oDes = document.querySelector("#des");
            var oImg = document.querySelector("img");
            // 2.获取所有按钮
            var oBtns = document.querySelectorAll("button");
            // 3.给按钮添加点击事件
            oBtns[0].onclick = function () {
                var self = this;
                // 4.发送Aajx请求到服务器
                ajax({
                    type:"get",
                    url:"10-ajax-test.php",
                    data:{"name":this.getAttribute("name")},
                    timeout: 3000,
                    success: function (xhr) {
                        /*
                        //PHP字典
                        // alert(xhr.responseText);
                        var res = xhr.responseText.split("|");
                        // console.log(res);
                        oTitle.innerHTML = res[0];
                        oDes.innerHTML = res[1];
                        oImg.setAttribute("src", res[2]);
                        */

                        /*
                        //获取XML数据
                        var name = self.getAttribute("name");
                        var res = xhr.responseXML;
                        var title = res.querySelector(name+">title").innerHTML;
                        var des = res.querySelector(name+">des").innerHTML;
                        var image = res.querySelector(name+">image").innerHTML;
                        oTitle.innerHTML = title;
                        oDes.innerHTML = des;
                        oImg.setAttribute("src", image);
                        */
                        var name = self.getAttribute("name");
                        var str = xhr.responseText;
                        var obj = JSON.parse(str);
                        // console.log(obj);
                        var subObj = obj[name];
                        // console.log(subObj);
                        oTitle.innerHTML = subObj.title;
                        oDes.innerHTML = subObj.des;
                        oImg.setAttribute("src", subObj.image);
                    },
                    error: function (xhr) {
                        alert(xhr.status);
                    }
                });
            }
            oBtns[1].onclick = function () {

            }
            oBtns[2].onclick = function () {

            }
        }
    </script>
</head>
<body>
<div>
    <p id="title">商品标题名称</p>
    <img src="" alt="">
    <p id="des">商品描述信息</p>
    <button name="nz">女装</button>
    <button name="bb">包包</button>
    <button name="tx">拖鞋</button>
</div>
</body>
</html>
<?php

// 1.定义字典保存商品信息
$products = array("nz"=>array("title"=>"甜美女装", "des"=>"人见人爱,花间花开,甜美系列", "image"=>"images/1.jpg"),
    "bb"=>array("title"=>"奢华驴包", "des"=>"送女友,送情人,送学妹,一送一个准系列", "image"=>"images/2.jpg"),
    "tx"=>array("title"=>"键盘拖鞋", "des"=>"程序员专属拖鞋, 屌丝气息浓郁, 你值得拥有", "image"=>"images/3.jpg"));
// 2.获取前端传递的参数
$name = $_GET["name"];
//echo $name;
// 3.根据前端传入的key,获取对应的字典
$product = $products[$name];
//print_r($product);
// 4.将小字典中的内容取出来返回给前端
echo $product["title"];
echo "|";
echo $product["des"];
echo "|";
echo $product["image"];


/*
// 执行结果中有中文, 必须在php文件顶部设置
//header("content-type:text/html; charset=utf-8");
// 如果PHP中需要返回XML数据, 也必须在PHP文件顶部设置
echo file_get_contents("10-ajax-test.xml");
*/

//echo file_get_contents("10-ajax-test.txt");   //有文件时
<?xml version="1.0" encoding="UTF-8" ?>
<products>
    <nz>
        <title>甜美|女装</title>
        <des>人见人爱,花间花开,甜美系列</des>
        <image>images/1.jpg</image>
    </nz>
    <bb>
        <title>奢华驴包</title>
        <des>送女友,送情人,送学妹,一送一个准系列</des>
        <image>images/2.jpg</image>
    </bb>
    <tx>
        <title>键盘拖鞋</title>
        <des>程序员专属拖鞋, 屌丝气息浓郁, 你值得拥有</des>
        <image>images/3.jpg</image>
    </tx>
</products>
{
    "nz":{
        "title":"甜美|女装",
        "des":"人见人爱,花间花开,甜美系列",
        "image":"images/1.jpg"
    },
    "bb":{
        "title":"奢华驴包",
        "des":"送女友,送情人,送学妹,一送一个准系列",
        "image":"images/2.jpg"
    },
    "tx":{
        "title":"键盘拖鞋",
        "des":"程序员专属拖鞋, 屌丝气息浓郁, 你值得拥有",
        "image":"images/3.jpg"
    }
}

4.jQuery中的AJAX

4.1 get 请求

$.get(url, [data], [callback], [type]) 

url:请求的 URL 地址。 

data:请求携带的参数。 

callback:载入成功时回调函数。 

type:设置返回内容格式,xml, html, script, json, text, _default。 

4.2 post 请求

$.post(url, [data], [callback], [type]) 

url:请求的 URL 地址。 

data:请求携带的参数。 

callback:载入成功时回调函数。 

type:设置返回内容格式,xml, html, script, json, text, _default。

4.3 AJAX

	<div class="container">
        <h2 class="page-header">jQuery发送AJAX请求 </h2>
        <button class="btn btn-primary">GET</button>
        <button class="btn btn-danger">POST</button>
        <button class="btn btn-info">通用型方法ajax</button>
    </div>
		$('button').eq(0).click(function(){
            $.get('http://127.0.0.1:8000/jquery-server', {a:100, b:200}, function(data){
                console.log(data);
            },'json');
        });

        $('button').eq(1).click(function(){
            $.post('http://127.0.0.1:8000/jquery-server', {a:100, b:200}, function(data){
                console.log(data);
            });
        });

        $('button').eq(2).click(function(){
            $.ajax({
                //url
                url: 'http://127.0.0.1:8000/jquery-server',
                //参数
                data: {a:100, b:200},
                //请求类型
                type: 'GET',
                //响应体结果
                dataType: 'json',
                //成功的回调
                success: function(data){
                    console.log(data);
                },
                //超时时间
                timeout: 2000,
                //失败的回调
                error: function(){
                    console.log('出错啦!!');
                },
                //头信息
                headers: {
                    c:300,
                    d:400
                }
            });
        });

服务器

//jQuery 服务
app.all('/jquery-server', (request, response) => {
    //设置响应头  设置允许跨域
    response.setHeader('Access-Control-Allow-Origin', '*');
    response.setHeader('Access-Control-Allow-Headers', '*');
    // response.send('Hello jQuery AJAX');
    const data = {name:'尚硅谷'};
    response.send(JSON.stringify(data));
});

5-axios-AJAX

github.com/axios/axios

	<button>GET</button>
    <button>POST</button>
    <button>AJAX</button>
        const btns = document.querySelectorAll('button');

        //配置 baseURL
        axios.defaults.baseURL = 'http://127.0.0.1:8000';

        btns[0].onclick = function () {
            //GET 请求
            axios.get('/axios-server', {
                //url 参数
                params: {
                    id: 100,
                    vip: 7
                },
                //请求头信息
                headers: {
                    name: 'atguigu',
                    age: 20
                }
            }).then(value => {
                console.log(value);
            });
        }

        btns[1].onclick = function () {
            //post(url[,data[,config]])
            axios.post('/axios-server', {
                username: 'admin',
                password: 'admin'
            }, {
                //url 
                params: {
                    id: 200,
                    vip: 9
                },
                //请求头参数
                headers: {
                    height: 180,
                    weight: 180,
                }
            });
        }
    
        btns[2].onclick = function(){
            axios({
                //请求方法
                method : 'POST',
                //url
                url: '/axios-server',
                //url参数
                params: {
                    vip:10,
                    level:30
                },
                //头信息
                headers: {
                    a:100,
                    b:200
                },
                //请求体参数
                data: {
                    username: 'admin',
                    password: 'admin'
                }
            }).then(response=>{
                //响应状态码
                console.log(response.status);
                //响应状态字符串
                console.log(response.statusText);
                //响应头信息
                console.log(response.headers);
                //响应体
                console.log(response.data);
            })
        }

服务器

//axios 服务
app.all('/axios-server', (request, response) => {
    //设置响应头  设置允许跨域
    response.setHeader('Access-Control-Allow-Origin', '*');
    response.setHeader('Access-Control-Allow-Headers', '*');
    // response.send('Hello jQuery AJAX');
    const data = {name:'尚硅谷'};
    response.send(JSON.stringify(data));
});

6-fetch-AJAX

developer.mozilla.org/zh-CN/docs/…

        const btn = document.querySelector('button');

        btn.onclick = function(){
            fetch('http://127.0.0.1:8000/fetch-server?vip=10', {
                //请求方法
                method: 'POST',
                //请求头
                headers: {
                    name:'atguigu'
                },
                //请求体
                body: 'username=admin&password=admin'
            }).then(response => {
                // return response.text();
                return response.json();
            }).then(response=>{
                console.log(response);
            });
        }

服务端

//fetch 服务
app.all('/fetch-server', (request, response) => {
    //设置响应头  设置允许跨域
    response.setHeader('Access-Control-Allow-Origin', '*');
    response.setHeader('Access-Control-Allow-Headers', '*');
    // response.send('Hello jQuery AJAX');
    const data = {name:'尚硅谷'};
    response.send(JSON.stringify(data));
});

7.跨域

7.1 同源策略

同源策略(Same-Origin Policy)最早由 Netscape 公司提出,是浏览器的一种安全策略。

同源: 协议、域名、端口号 必须完全相同。 

违背同源策略就是跨域。 
    <h1>尚硅谷</h1>
    <button>点击获取用户数据</button>
        const btn = document.querySelector('button');

        btn.onclick = function(){
            const x = new XMLHttpRequest();
            //这里因为是满足同源策略的, 所以 url 可以简写
            x.open("GET",'/data');
            //发送
            x.send();
            //
            x.onreadystatechange = function(){
                if(x.readyState === 4){
                    if(x.status >= 200 && x.status < 300){
                        console.log(x.response);
                    }
                }
            }
        }
const express = require('express');

const app = express();

app.get('/home', (request, response)=>{
    //响应一个页面
    response.sendFile(__dirname + '/index.html');
});

app.get('/data', (request, response)=>{
    response.send('用户数据');
});

app.listen(9000, ()=>{
    console.log("服务已经启动...");
});

7.2 如何解决跨域

7.2.1 JSONP

1. JSONP 是什么
JSONP(JSON with Padding),是一个非官方的跨域解决方案,纯粹凭借程序员的聪明才智开发出来,只支持 get 请求。 
标签可以跨域
function handle(data) {
    //获取 result 元素
    const result = document.getElementById('result');
    result.innerHTML = data.name;
}
<script src="http://127.0.0.1:8000/jsonp-server"></script>
//jsonp服务
app.all('/jsonp-server',(request, response) => {
    // response.send('console.log("hello jsonp")');  //返回的要像这样是一段js代码
    const data = {
        name: '尚硅谷atguigu'
    };
    //将数据转化为字符串
    let str = JSON.stringify(data);
    //返回结果
    response.end(`handle(${str})`);
});
2. JSONP 怎么工作的?
在网页有一些标签天生具有跨域能力,比如:img link iframe script。JSONP 就是利用 script 标签的跨域能力来发送请求的。 
3. JSONP 的使用
 1.动态的创建一个 script 标签 

    var script = document.createElement("script"); 

2.设置 script 的 src,设置回调函数 

    script.src = "http://localhost:3000/testAJAX?callback=abc"; 

    function abc(data) { 

        alert(data.name); 

    }; 

3.将 script 添加到 body 中 

    document.body.appendChild(script); 

4.服务器中路由的处理 

    router.get("/testAJAX" , function (req , res) { 

        console.log("收到请求"); 

        var callback = req.query.callback; 

        var obj = { 

            name:"孙悟空", 

            age:18 

        }

        res.send(callback+"("+JSON.stringify(obj)+")"); 

    }); 
4.实践
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>案例</title>
</head>
<body>
    用户名: <input type="text" id="username">
    <p></p>
    <script>
        //获取 input 元素
        const input = document.querySelector('input');
        const p = document.querySelector('p');
        
        //声明 handle 函数
        function handle(data){
            input.style.border = "solid 1px #f00";
            //修改 p 标签的提示文本
            p.innerHTML = data.msg;
        }

        //绑定事件 失去焦点后
        input.onblur = function(){
            //获取用户的输入值
            let username = this.value;
            //向服务器端发送请求 检测用户名是否存在
            //1. 创建 script 标签
            const script = document.createElement('script');
            //2. 设置标签的 src 属性
            script.src = 'http://127.0.0.1:8000/check-username';
            //3. 将 script 插入到文档中
            document.body.appendChild(script);
        }
    </script>
</body>
</html>
//用户名检测是否存在
app.all('/check-username',(request, response) => {
    // response.send('console.log("hello jsonp")');
    const data = {
        exist: 1,
        msg: '用户名已经存在'
    };
    //将数据转化为字符串
    let str = JSON.stringify(data);
    //返回结果
    response.end(`handle(${str})`);
});
5. jQuery 中的 JSONP
<body> 
    <button id="btn">按钮</button> 
    <ul id="list"></ul>
    <script type="text/javascript" src="./jquery-1.12.3.js"></script>
    <script type="text/javascript">
        window.onload = function () {
            var btn = document.getElementById('btn') btn.onclick = function () {
                $.getJSON("http://api.douban.com/v2/movie/in_theaters?callback=?",function (data) {
                    console.log(data); 
                    //获取所有的电影的条目 
                    var subjects = data.subjects; 
                    //遍历电影条目
                    for(var i=0 ; i<subjects.length ; i++){
                        $("#list").append("<li>"+ subjects[i].title+"<br />"+ "<img src=\""+subjects[i].images.large+"\" >"+ "</li>");
                    }
                });
            }
        }
    </script> 
</body> 
//此案例
<body>
    <button>点击发送 jsonp 请求</button>
    <div id="result">

    </div>
    <script>
        $('button').eq(0).click(function(){
            $.getJSON('http://127.0.0.1:8000/jquery-jsonp-server?callback=?', function(data){
                $('#result').html(`
                    名称: ${data.name}<br>
                    校区: ${data.city}
                `)
            });
        });
    </script>
</body>
app.all('/jquery-jsonp-server',(request, response) => {
    // response.send('console.log("hello jsonp")');
    const data = {
        name:'尚硅谷',
        city: ['北京','上海','深圳']
    };
    //将数据转化为字符串
    let str = JSON.stringify(data);
    //接收 callback 参数
    let cb = request.query.callback;

    //返回结果
    response.end(`${cb}(${str})`);
});

7.2.2 CORS

developer.mozilla.org/zh-CN/docs/…

1)CORS 是什么?
CORS(Cross-Origin Resource Sharing),跨域资源共享。CORS 是官方的跨域解决方案,它的特点是不需要在客户端做任何特殊的操作,完全在服务器中进行处理,支持get 和 post 请求。跨域资源共享标准新增了一组 HTTP 首部字段,允许服务器声明哪些源站通过浏览器有权限访问哪些资源 
2)CORS 怎么工作的?
CORS 是通过设置一个响应头来告诉浏览器,该请求允许跨域,浏览器收到该响应以后就会对响应放行。 
3)CORS 的使用
主要是服务器端的设置: 

router.get("/testAJAX" , function (req , res) 

    //通过 res 来设置响应头,来允许跨域请求 

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

    res.set("Access-Control-Allow-Origin","*"); 

    res.send("testAJAX 返回的响应"); 

}); 
app.all('/cors-server', (request, response)=>{
    //设置响应头
    response.setHeader("Access-Control-Allow-Origin", "*");
    response.setHeader("Access-Control-Allow-Headers", '*');
    response.setHeader("Access-Control-Allow-Method", '*');
    // response.setHeader("Access-Control-Allow-Origin", "http://127.0.0.1:5500");
    response.send('hello CORS');
});
btn.onclick = function(){
    //1. 创建对象
    const x = new XMLHttpRequest();
    //2. 初始化设置
    x.open("GET", "http://127.0.0.1:8000/cors-server");
    //3. 发送
    x.send();
    //4. 绑定事件
    x.onreadystatechange = function(){
        if(x.readyState === 4){
            if(x.status >= 200 && x.status < 300){
                //输出响应体
                console.log(x.response);
            }
        }
    }
}

PHP

<?php
// 1.JS中有两种注释
// 1.1单行注释
// 1.2多行注释
//
/* */

// 2.JS中如何定义变量?
//var num = 10;
$num = 10;

// 3.JS中如何打印内容?
//console.log();
// 注意点: 后端编写的代码不能直接运行, 只能放到服务器对应的文件夹下, 通过服务器运行
// 如何通过服务器运行: 通过ip地址找到服务器对应的文件夹, 然后再找到对应的文件运行
echo $num;

// 4.JS中如何定义集合
// 4.1数组
// 4.2字典(对象)
//var arr = [1, 3, 5];
// arr[0];
//$arr = array(1, 3, 5);
print_r($arr);			//echo不能输出集合、字典 用这种方法可以
//echo "<br>";
echo $arr[1];		//取出特定索引的值
//字典
//var dict = {"name":"lnj", "age":"33"};
// dict["name"];
$dict = array("name"=>"lnj", "age"=>"33");
print_r($dict);
//echo  "<br>";
echo $dict["name"];

// 5.JS中的分支循环语句
// if/switch/三目/for/while
$age = 16;
if($age >= 18){
    echo "成年人";
}else{
    echo "未成年人";
}

$res = ($age >= 18) ? "成年人" : "未成年人";
echo $res;

switch ($age){
    case -1:
        echo "非人类";
        break;
    case 18:
        echo "成年人";
        break;
    default:
        echo "未成年人";
        break;
}

$arr = array(1, 3, 5);
//for($i = 0; $i < count($arr); $i++){
//    echo $arr[$i];
//    echo "<br>";
//}
$index = 0;
while ($index < count($arr)){
    echo $arr[$index];
    echo "<br>";
    $index++;
}
?>

XML

可扩展的文件语言,固定开头,根标签可以自定义

<?xml version="1.0" encoding="UTF-8" ?>

前端获取

// console.log(xhr.responseXML);
// console.log(document);
var res = xhr.responseXML;
console.log(res.querySelector("name").innerHTML);
console.log(res.querySelector("age").innerHTML);

php

<?php
// 执行结果中有中文, 必须在php文件顶部设置
//header("content-type:text/html; charset=utf-8");
// 如果PHP中需要返回XML数据, 也必须在PHP文件顶部设置
header("content-type:text/xml; charset=utf-8");

echo file_get_contents("info.xml");

JSON

JSON 是 JS 对象的字符串表示法,它使用文本表示一个 JS 对象的信息,本质是一个字符串。
如
var obj = {a: 'Hello', b: 'World'}; //这是一个对象,注意键名也是可以使用引号包裹的
var json = '{"a": "Hello", "b": "World"}'; //这是一个 JSON 字符串,本质是一个字符串

JSON 和 JS 对象互转
要实现从JSON字符串转换为JS对象,使用 JSON.parse() 方法:
var obj = JSON.parse('{"a": "Hello", "b": "World"}'); //结果是 {a: 'Hello', b: 'World'}
要实现从JS对象转换为JSON字符串,使用 JSON.stringify() 方法:
var json = JSON.stringify({a: 'Hello', b: 'World'}); //结果是 '{"a": "Hello","b":"World"}'

{
    "name":"lnj",
    "age":"33"
}
<?php

echo file_get_contents("12-ajax-json.txt");
ajax({
    type:"get",
    url:"12-ajax-json.php",
    success: function (xhr) {
        // console.log(xhr.responseText);
        var str = xhr.responseText;
        var obj = JSON.parse(str);
        // console.log(obj);
        console.log(obj.name);
        console.log(obj.age);
    },
    error: function (xhr) {
        console.log(xhr.status);
    }
})

cookie

            /*
            cookie: 会话跟踪技术 客户端
            session:  会话跟踪技术  服务端

            cookie作用:
            将网页中的数据保存到浏览器中

            cookie生命周期:
            默认情况下生命周期是一次会话(浏览器被关闭)
            如果通过expires=设置了过期时间, 并且过期时间没有过期, 那么下次打开浏览器还是存在
            如果通过expires=设置了过期时间, 并且过期时间已经过期了,那么会立即删除保存的数据

            cookie注意点:
            cookie默认不会保存任何的数据
            cookie不能一次性保存多条数据, 要想保存多条数据,只能一条一条的设置
            cookie有大小和个数的限制
            个数限制: 20~50
            大小限制: 4KB左右

            cookie作用范围:
            同一个浏览器的同一个路径下访问
            如果在同一个浏览器中, 默认情况下下一级路径就可以访问
            如果在同一个浏览器中, 想让上一级目录也能访问保存的cookie, 那么需要添加一个path属性才可以;
            document.cookie = "name=zs;path=/;";

            例如:
            保存到了www.it666.com/jQuery/Ajax/路径下,
            我们想在 www.it666.com/jQuery/Ajax/13-weibo/,
            和 www.it666.com/jQuery/ 路径下也能访问

            例如:
            我们在www.it666.com下面保存了一个cookie,
            那么我们在edu.it666.com中是无法访问的
            如果想在edu.it666.com中也能访问, 那么我们需要再添加一个domain属性才可以;
            document.cookie = "name=zs;path=/;domain=it666.com;";
            */

            // alert(document.cookie);
            // var date = new Date();
            // date.setDate(date.getDate() - 1);
            // document.cookie = "age=33;expires="+date.toGMTString()+";";
            // alert(document.cookie);

            // document.cookie = "name=lnj;";
            // document.cookie = "age=33;";
            // alert(document.cookie);
            // document.cookie = "name=lnj;age=33;gender=male;";

            document.cookie = "name=zs;path=/;domain=127.0.0.1;";

封装

            // addCookie("score", "998", 1, "/", "127.0.0.1");
            function addCookie(key, value, day, path, domain) {
                // 1.处理默认保存的路径
                // if(!path){
                //     var index = window.location.pathname.lastIndexOf("/")
                //     var currentPath = window.location.pathname.slice(0, index);
                //     path = currentPath;
                // }
                var index = window.location.pathname.lastIndexOf("/")
                var currentPath = window.location.pathname.slice(0, index);
                path = path || currentPath;
                // 2.处理默认保存的domain
                domain = domain || document.domain;
                // 3.处理默认的过期时间
                if(!day){
                    document.cookie = key+"="+value+";path="+path+";domain="+domain+";";
                }else{
                    var date = new Date();
                    date.setDate(date.getDate() + day);
                    document.cookie = key+"="+value+";expires="+date.toGMTString()+";path="+path+";domain="+domain+";";
                }
            }

            function getCookie(key) {
                // console.log(document.cookie);
                var res = document.cookie.split(";");
                // console.log(res);
                for(var i = 0; i < res.length; i++){
                    // console.log(res[i]);
                    var temp = res[i].split("=");
                    // console.log(temp);
                    if(temp[0].trim() === key){
                        return temp[1];
                    }
                }
            }
            console.log(getCookie("name"));

            // 默认情况下只能删除默认路径中保存的cookie, 如果想删除指定路径保存的cookie, 那么必须在删除的时候指定路径才可以
            function delCookie(key, path) {
                addCookie(key, getCookie(key), -1, path);
            }
            delCookie("name", "/");

hash

window.location.hash = 3;    //网站尾部#3 种哈希
console.log(window.location.hash.substring(1));		//截取#,获取hash值