第二部分 Ajax 编程扩展

 学习内容及目标: 模板引擎,案例,FormData,同源政策

 

1,模板引擎

在传统网站中,客户端向服务器端发送请求,服务器将html + 数据拼接好 发送给客户端,现在使用Ajax技术向服务器发送请求,服务器大多数都是用json 数据格式作为响应内容,也就是说,原本数据+html 的拼接在服务器端完成,现在在客户端完成,在客户端做数据拼接 我们也需要使用模板引擎;现在看的是客户端模板引擎, art-template也有客户端版本

1.1 模板引擎 概述

作用:使用模板引擎提供的模板语法,可以将数据和 HTML 拼接起来

官方地址: https://aui.github.io/art-template/zh-cn/index.html

下载到我们的项目文件夹里 template-web.js

1.2 使用步骤

1下载 art-template 模板引擎库文件并在 HTML 页面中引入

<script src="./js/template-web.js"></script>

2.   准备 art-template 模板:利用模板语法将HTML+数据拼接起来的地方;注意,客户端JS没有读取文件的能力,所以在客户端不是一个单独的文件,而是HTML文件中一个代码片段,并用 script包裹,需要有一个id作为模板的唯一标识,在 script标签内部,写HTML语法,但是由于 script内部编辑器会作为 JS语法解析,也灭有高亮提示?【如何解决:】 script标签上添加type属性 type="text/html"

      <script id="tpl" type="text/html">

               <div class="box"></div>

       </script>

3.   告诉模板引擎将哪一个模板和哪个数据进行拼接,如何告诉呢? Template()方法返回拼接好的字符串

var html = template('tpl=模板id', {username: 'zhangsan', age: '20'}=对象,模板中展示的数据,可以在HTML中可以通过对象。属性 获取属性对应的值);

4.   将拼接好的html字符串添加到页面中,通过DOM 方法获取页面中的存储容器,并将拼接好的HTML字符串放在容器中,这里还挺简单的哈

document.getElementById('container').innerHTML = html;

5.   通过模板语法告诉模板引擎,数据和html字符串要如何拼接,重要的一步!!node中一样

<script id="tpl" type="text/html">

         <div class="box"> {{ username }} </div>

       </script>

看一下实例代码哈~:D????

09【Ajax 】第二部分:Ajax 编程扩展, 模板引擎,案例,FormData,同源政策

09【Ajax 】第二部分:Ajax 编程扩展, 模板引擎,案例,FormData,同源政策

 

 

 

2.案例

2.1 验证邮箱地址唯一性

  1. 获取文本框并为 其添加离开焦点事件
  2. 离开焦点时,检测用户输入的邮箱地址是否符合规则
  3. 如果不符合规则,阻止程序向下执行并给出提示信息
  4. 向服务器端发送请求,检测邮箱地址是否被别人注册
  5. 根据服务器端返回值决定客户端显示何种提示信息
  6. /^[A-Za-z\d]+([-_.][A-Za-z\d]+)*@([A-Za-z\d]+[-.])+[A-Za-z\d]{2,4}$/

09【Ajax 】第二部分:Ajax 编程扩展, 模板引擎,案例,FormData,同源政策

ajax.js 发送请求 封装函数代码 O(∩_∩)O~~

function ajax (options) {

    // 认值

    var defaults = {

        type: 'get',

        url: '',

        async: true,

        data: {},

        header: {

            'Content-Type': 'application/x-www-form-urlencoded'

        },

        success: function () {},

        error: function () {}

    }

    // 使用用户传递参数认值参数

    Object.assign(defaultsoptions);

    // ajax

    var xhr = new XMLHttpRequest();

    // 参数拼

    var params = '';

    // 环参数

    for (var attr in defaults.data) {

        // 参数拼

        params += attr + '=' + defaults.data[attr] + '&';

        // 去掉参数中最后一&

        params = params.substr(0params.length-1)

    }

    // 如果求方式get

    if (defaults.type == 'get') {

        // 将参数拼接在url地址的后面

        defaults.url += '?' + params;

    }

 

    // 配置ajax

    xhr.open(defaults.typedefaults.urldefaults.async);

    // 如果求方式post

    if (defaults.type == 'post') {

        // 

        xhr.setRequestHeader('Content-Type'defaults.header['Content-Type']);

        // 如果想服器端传递参数类json

        if (defaults.header['Content-Type'] == 'application/json') {

            // json转换为json字符串

            xhr.send(JSON.stringify(defaults.data))

        }else {

            // 

            xhr.send(params);

        }

    } else {

        xhr.send();

    }

    // 求加完成

    xhr.onload = function () {

        // 取服器端返回据的

        var contentType = xhr.getResponseHeader('content-type');

        // 取服器端返回的响应数

        var responseText = xhr.responseText;

        // 如果服器端返回的据是json

        if (contentType.includes('application/json')) {

            // json字符串转换为json

            responseText = JSON.parse(responseText);

        }

        // 如果求成功

        if (xhr.status == 200) {

            // 用成功回器端返回的传递给成功回

            defaults.success(responseTextxhr);

        } else {

            // 用失数并xhr传递给

            defaults.error(responseTextxhr);

        

    }

    // 当网络断时

    xhr.onerror = function () {

        // 用失数并xhr传递给

        defaults.error(xhr);

    }

}

 

09【Ajax 】第二部分:Ajax 编程扩展, 模板引擎,案例,FormData,同源政策

02.验证邮箱地址唯一性.html

<!DOCTYPE html>

<html lang="en">

<head>

    <meta charset="UTF-8">

    <title>验证邮箱地址是否已</title>

    <link rel="stylesheet" href="/assets/bootstrap/dist/css/bootstrap.min.css">

    <style type="text/css">

        p:not(:empty) {

            padding15px;

        }

        .container {

            padding-top100px;

        }

    </style>

</head>

<body>

    <div class="container">

        <div class="form-group">

            <label>箱地址</label>

            <input type="email" class="form-control" placeholder="请输箱地址" id="email">

        </div>

        <!-- 错误 bg-danger 正确 bg-success -->

        <p id="info"></p>

    </div>

    <script src="/js/ajax.js"></script>

    <script>

        // 1 面中的元素

        var emailInp = document.getElementById('email');

        var info = document.getElementById('info');

 

        // 2 文本框离焦点以后 onblur

        emailInp.onblur = function () {

            // 2.1 取用户输入的箱地址 this 代表 生事件的元素 = 文本框

            var email = this.value;

            // 2.2 验证邮箱地址的正

            var reg = /^[A-Za-z\d]+([-_.][A-Za-z\d]+)*@([A-Za-z\d]+[-.])+[A-Za-z\d]{2,4}$/;

            // 2.3 如果用户输入的箱地址不符合规则

            if (!reg.test(email)) {

                // 出用提示

                info.innerHTML = '请输入符合规则箱地址';

                // 提示信息为错误提示信息的

                info.className = 'bg-danger';

                // 阻止程序向下

                return;

            }

 

            // 向服器端求,引入Ajax求函,直接ajax

            ajax({

                type: 'get',

                url: 'http://localhost:3000/verifyEmailAdress',

                data: {

                    email: email // 参数Email定的参数名,用户输入的箱地址验证邮

                },

                success: function (result) {

                    console.log(result);

                    info.innerHTML = result.message;

                    info.className = 'bg-success';

                },

                error: function (result) {

                    console.log(result)

                    info.innerHTML = result.message;

                    info.className = 'bg-danger';

                }

            });

        }

    </script>

</body>

</html>

 

App.js

// 箱地址验证

app.get('/verifyEmailAdress', (reqres=> {

    // 接收客传递过来箱地址

    const email = req.query.email;

    // 断邮箱地址注册过的情

    if (email == '[email protected]') {

        // http状态码并对端做出响应

        res.status(400).send({message: '箱地址已册过其他箱地址'});

    } else {

        // 箱地址可用的情

        // 端做出响应

        res.send({message: '恭喜箱地址可用'});

    } 

});

 

2.2 搜索框内容自动提示

  1. 获取搜索框并为其添加用户输入事件
  2. 获取用户输入的关键字
  3. 向服务器端发送请求携带关键字作为请求参数
  4. 将响应数据显示在搜索框底部

09【Ajax 】第二部分:Ajax 编程扩展, 模板引擎,案例,FormData,同源政策

09【Ajax 】第二部分:Ajax 编程扩展, 模板引擎,案例,FormData,同源政策

【问题1

请求的发送和携带的参数,第一次携带参数是c , 第二次是ch, 第三次chu, 这就是不合理的,发送了很多无意义的请求?如何解决?

用户连续输入,输入字符比较快,时间间隔比较短;利用时间间隔解决?

在输入事件oninput 触发是,包裹一个延时定时器,让他不要连续触发;

连续输入,oninput 会被持续触发,先将上一次开启的延时定时器清除,上一次输入请求不会发送,在开启一个新的定时器,用于当前输入发送,循环往复,知道输入完成,才会发送

大大减少了无意义请求的次数;

【问题2

清除搜索框,下边的提示文字,也要隐藏;

在发生oninput 的时候,判断用户输入的值,如果没有输入内容,要隐藏下拉提示框listBox.style.display = ‘none’; 并且阻止程序向下执行 return;

 

03.搜索框内容自动提示.html

<!DOCTYPE html>

<html lang="en">

<head>

    <meta charset="UTF-8">

    <title>搜索框入文字自提示</title>

    <link rel="stylesheet" href="/assets/bootstrap/dist/css/bootstrap.min.css">

    <style type="text/css">

        .container {

            padding-top150px;

        }

        .list-group {

            displaynone;

        }

    </style>

</head>

<body>

    <div class="container">

        <div class="form-group">

            <input type="text" class="form-control" placeholder="请输入搜索关键" id="search">

            <ul class="list-group" id="list-box">

                

            </ul>

        </div>

    </div>

    <script src="/js/ajax.js"></script>

    <script src="/js/template-web.js"></script>

    <script type="text/html" id="tpl"> 

        {{each result}}

            <li class="list-group-item">{{$value}}</li>

        {{/each}}

    </script>

    <script>

        // 1取搜索框 getElementById,返回一searchInp

        var searchInp = document.getElementById('search');

        // 2取提示文字的存放容器,返回存在listBox

        var listBox = document.getElementById('list-box');

        // 器的

        var timer = null;

 

        // 3在搜索框中入的触发 oninput户输入事件

        searchInp.oninput = function () {

            // 除上一次开启的定

            clearTimeout(timer);

 

            // 3.1 取用户输入的容,接下要向服器端据了,但是传递参数都不知道,需要看接口文

            var key = this.value;

            // 3.2 如果用户没有在搜索框中

            if (key.trim().length == 0) {

                // 提示下拉框藏掉

                listBox.style.display = 'none';

                // 阻止程序向下

                return;

            }

 

            // 开启 让请求延迟发

            timer = setTimeout(function () {

                //4 向服器端求:向服器端索取和用户输关键字相

                ajax({

                    type: 'get'//可以不,默就是get

                    url: 'http://localhost:3000/searchAutoPrompt'//求地址

                    data: { // 求需要我们传入一个参数

                        key: key 

                    }, 

                    // success,形是服返回的据,返回是一个数组,和用户输入的关键字相

                    // 数组li接,最接的果放在 ul 标签

                    success: function (result) {

                        // 使用模板引擎接字符串:参数:那模板+个数据:就是形result

                        var html = template('tpl', {result: result});

                        // 将拼接好的字符串示在面中 ul容器listBox

                        listBox.innerHTML = html;

                        // ul 藏的,ul容器

                        listBox.style.display = 'block';

                    }

                })

            }, 800)

        }

    </script>

</body>

</html

spp.js

09【Ajax 】第二部分:Ajax 编程扩展, 模板引擎,案例,FormData,同源政策

2.3 省市区三级联动

需求:当用户选择省份后,城市下拉框要显示对应省份的城市信息,当用户选择城市下拉框中某一城市,要显示城市对应县城或者区下拉框信息,

  1. 通过接口获取 省份信息
  2. 使用JavaScript获取到省市区下拉框元素
  3. 将服务器端返回的省份信息显示在下拉框中:模板引擎
  4. 为下拉框元素添加 表单值改变 事件(onchange):会在用户将下拉框的值改变时触发
  5. 当用户选择省份时,根据省份id获取城市信息
  6. 当用户选择城市时,根据城市id获取县城信息

09【Ajax 】第二部分:Ajax 编程扩展, 模板引擎,案例,FormData,同源政策

09【Ajax 】第二部分:Ajax 编程扩展, 模板引擎,案例,FormData,同源政策09【Ajax 】第二部分:Ajax 编程扩展, 模板引擎,案例,FormData,同源政策

09【Ajax 】第二部分:Ajax 编程扩展, 模板引擎,案例,FormData,同源政策

【问题】

当第一次选择完成后,当再次选择省份的时候,清空县城下的下拉框数据;使用模板方式;

 

04.省市区联动.html

<!DOCTYPE html>

<html lang="en">

<head>

    <meta charset="UTF-8">

    <title>搜索框入文字自提示</title>

    <link rel="stylesheet" href="/assets/bootstrap/dist/css/bootstrap.min.css">

    <style type="text/css">

        .container {

            padding-top150px;

        }

    </style>

</head>

<body>

    <div class="container">

        <div class="form-inline">

            <div class="form-group">

                <select class="form-control" id="province"></select>

            </div>

            <div class="form-group">

                <select class="form-control" id="city">

                    <option>请选择城市</option>

                </select>

            </div>

            <div class="form-group">

                <select class="form-control" id="area">

                    <option>请选择县</option>

                </select>

            </div>

        </div>

    </div>

    <script src="/js/ajax.js"></script>

    <script src="/js/template-web.js"></script>

    <!-- 模板 -->

    <script type="text/html" id="provinceTpl">

        <option>请选择</option> 

        {{each province}}

            <option value="{{$value.id}}">{{$value.name}}</option>

        {{/each}}

    </script>

    <!-- 城市模板 -->

    <script type="text/html" id="cityTpl">

        <option>请选择城市</option>

        {{each city}}

            <option value="{{$value.id}}">{{$value.name}}</option>

        {{/each}}

    </script>

    <!-- 城模板 -->

    <script type="text/html" id="areaTpl">

        <option>请选择县</option>

        {{each area}}

            <option value="{{$value.id}}">{{$value.name}}</option>

        {{/each}}

    </script>

    <script>

        // 2取省市下拉框元素

        var province = document.getElementById('province');

        var city = document.getElementById('city');

        var area = document.getElementById('area');

        // 1取省信息

        ajax({

            type: 'get',

            url: 'http://localhost:3000/province',

            success: function (data) {

                // 器端返回的 data html

                var html = template('provinceTpl', {province: data});

                // 将拼接好的html字符串示在面中

                province.innerHTML = html;

            }

        });

 

        // 的下拉框添加事件

        province.onchange = function () {

            // 取省id

            var pid = this.value;

 

            // 城下拉框中的

            var html = template('areaTpl', {area: []});

            area.innerHTML = html;

 

            // 根据省id取城市信息

            ajax({

                type: 'get',

                url: '/cities',

                data: {

                    id: pid

                },

                success: function (data) {

                    var html = template('cityTpl', {city: data});

                    city.innerHTML = html;

                }

            })

        };

 

        // 户选择城市的

        city.onchange = function () {

            // 取城市id

            var cid = this.value;

            // 根据城市id城信息

            ajax({

                type: 'get',

                url: 'http://localhost:3000/areas',

                data: {

                    id: cid

                },

                success: function(data) {

                    var html = template('areaTpl', {area: data});

                    area.innerHTML = html;

                }

            })

        }

    </script>

</body>

</html>

// 取省

app.get('/province', (reqres=> {

    res.json([{

        id: '001',

        name: '江省'

    },{

        id: '002',

        name: '四川省'

    },{

        id: '003',

        name: '河北省'

    },{

        id: '004',

        name: ''

    }]);

});

 

// 根据省id取城市

app.get('/cities', (reqres=> {

    // 取省id

    const id = req.query.id;

    // 城市信息

    const cities = {

        '001': [{

            id: '300',

            name: '哈尔'

        }, {

            id: '301',

            name: '齐齐哈尔市'

        }, {

            id: '302',

            name: '牡丹江市'

        }, {

            id: '303',

            name: '佳木斯市'

        }],

        '002': [{

            id: '400',

            name: '成都市'

        }, {

            id: '401',

            name: '绵阳'

        }, {

            id: '402',

            name: ''

        }, {

            id: '403',

            name: '攀枝花市'

        }],

        '003': [{

            id: '500',

            name: '石家庄市'

        }, {

            id: '501',

            name: '唐山市'

        }, {

            id: '502',

            name: '秦皇'

        }, {

            id: '503',

            name: ''

        }],

        '004': [{

            id: '600',

            name: '常州市'

        }, {

            id: '601',

            name: '徐州市'

        }, {

            id: '602',

            name: '南京市'

        }, {

            id: '603',

            name: '淮安市'

        }]

    }

    // 响应

    res.send(cities[id]);

});

 

// 根据城市id

app.get('/areas', (reqres=> {

    // 取城市id

    const id = req.query.id;

    // 城信息

    const areas = {

        '300': [{

            id: '20',

            name: '道里',

        }, {

            id: '21',

            name: '岗区'

        }, {

            id: '22',

            name: '平房',

        }, {

            id: '23',

            name: '松北'

        }],

        '301': [{

            id: '30',

            name: ''

        }, {

            id: '31',

            name: '铁锋区'

        }, {

            id: '32',

            name: '富拉尔基'

        }]

    };

    // 响应

    res.send(areas[id] || []);

});

 

3.FormData

3.1 FormData 对象的作用

可以帮助我们解决当前Ajax代码中的一些问题,比如,当如我们要发送请求,参数比较多的时候,参数值的获取,和参数格式的拼接,就像注册用户,需要填写用户名,密码,确认密码,邮箱等,需要挨个获取表单控件以及它的值,还要按照制定的格式进行字符串拼接,代码繁琐

再比如,普通的Ajax是不能传 二进制文件的,比如图片

使用formData 就可以解决这些问题

1)模拟HTML表单,相当于将HTML表单映射成表单对象自动将表单对象中的数据拼接成请求参数的格式。将表单对象 作为请求参数 传到服务器端,就省去了空间值,表单控件的获取,参数值的拼接

2)异步上传二进制文件;图片,视频等

3.2 FormData 对象的使用

第一种使用场景:转换为表单对象,作为参数传递到服务器

1).  准备 HTML 表单:不需要设置请求地址和请求方式和表单提交按钮,因为不是传统的表单提交,要发送Ajax请求,这些都在Ajax请求中设置但是在表单控件中一定要有name属性,因为在表单提交时,需要将表单内容作为请求参数给服务器,name作为请求参数的属性名称

<form id="form">

     <input type="text" name="username" />

     <input type="password" name="password" />

     <input type="button"/>

</form>

2).  将 HTML 表单转化为 formData 表单对象: formData本身是一个构造函数,可以创建 formData对象,可以接受一个表单DOM 对象作为参数,构造函数会自动将表单控件中的数据拼接成请求参数所需要的格式,也就是说,需要通过DOM获取表单,获取结果传到formData构造函数中

var form = document.getElementById('form');

var formData = new FormData(form);

3).  提交表单对象:创建的表单对象放在Ajax中的 xhr.send()方法中, 就省去了空间值,表单控件的获取,参数值的拼接

xhr.send(formData);

注意:

  1. Formdata 对象不能用于 get 请求,因为对象需要被传递到 send 方法中,而 get 请求方式的请求参数 只能放在请求地址的后面
  2. 服务器端 bodyParser 模块不能解析 formData 对象表单数据,我们需要使用 formidable 模块进行解析

05.FormData对象的使用方法.html

<!DOCTYPE html>

<html lang="en">

<head>

    <meta charset="UTF-8">

    <title>Document</title>

</head>

<body>

    <!-- 1建普通的html :  不需要有actionmethod性,因做的不是传统的表提交,而是Ajax提交,提交,name性作为请参数性名-->

    <form id="form">

        <input type="text" name="username">

        <input type="password" name="password">

        <!-- 不是submit ,因他有默的提交行 -->

        <input type="button" id="btn" value="提交">

    </form>

    <script type="text/javascript">

        // 2取按,添加事件

        var btn = document.getElementById('btn');

        // 3取表

        var form = document.getElementById('form');

        // 4添加点事件

        btn.onclick = function () {

            // 4.1 普通的html单转换为单对象,参数DOM象,将哪单转换formDate

            var formData = new FormData(form);

 

            // ajax象:把表单对象提交到服

            var xhr = new XMLHttpRequest();

            // ajax行配置:xhr.open(); 求方式一定是post,因formData 放在 send()方法中,get参数url 

            xhr.open('post''http://localhost:3000/formData');

            // ajax

            xhr.send(formData);

            

            // xhr象下面的onload事件

            xhr.onload = function () {

                // http状态码进行判

                if (xhr.status == 200) {

                    console.log(xhr.responseText);

                }

            }

        }

    </script>

</body>

</html>

服务器端代码 app.js  

const formidable = require('formidable');

app.post('/formData', (reqres=> {

// formidable解析

// 之前使用body-pareser接受客传来post参数,但是不能formData

    const form = new formidable.IncomingForm();

    // 解析客传递过来FormData: fields 里边保存了这个表单中普通请求参数,files保存和文件上传相关信息

    form.parse(req, (errfieldsfiles=> {

        res.send(fields);

    });

});

09【Ajax 】第二部分:Ajax 编程扩展, 模板引擎,案例,FormData,同源政策

09【Ajax 】第二部分:Ajax 编程扩展, 模板引擎,案例,FormData,同源政策

3.3 FormData 对象的实例方法

对表单对象中 数据的操作,一般来说,表单数据一般不会被直接提交到服务器端的,用户填写数据以点击提交按钮后,对用户填的数据进行校验,要获取用户输入的值,对其检验或者修改等

1).  获取表单对象中属性的值  formData.get('key')

2).  设置表单对象中属性的值  formData.set('key', 'value'); set()可以用在表单数据的二次处理上,用户发布文章,没有设置时间;用户在文本框输入钱的数,服务器要求保留两位小数;获取用户输入值,为这个值保留两位小数,在设置回表单对象中

3).  删除表单对象中属性的值  formData.delete('key'); 用户注册,必须输入两次密码,必须一致,向服务器只提交一次

4).  向表单对象中追加属性值  formData.append('key', 'value'); 创建 formData可以不传DOM对象做参数,代表创建一个空的 formData对象

注意:set 方法与 append 方法的区别是,在属性名已存在的情况下set 会覆盖已有键名的值,append会保留两个值。

// 06.FormData象下的例方法.html

<!DOCTYPE html>

<html lang="en">

<head>

    <meta charset="UTF-8">

    <title>Document</title>

</head>

<body>

    <!-- 建普通的html -->

    <form id="form">

        <input type="text" name="username">

        <input type="password" name="password">

        <input type="button" id="btn" value="提交">

    </form>

    <script type="text/javascript">

        // 取按

        var btn = document.getElementById('btn');

        // 取表

        var form = document.getElementById('form');

        // 添加点事件

        btn.onclick = function () {

            // 普通的html单转换为单对

            var formData = new FormData(form);

            /*

                get('key') 取表单对性的

                set('key', 'value') 置表单对性的

                delete('key') 除表单对性中的

            */

            console.log(formData.get('username')); 

 

            // 如果置的表单属性存在 将会覆盖性原有的

            formData.set('username''itcast');

            formData.append('username''itheima');

            // 如果置的表单属性不存在 将会创这个单属

            formData.set('age'100);

            // 除用户输入的密

            formData.delete('password');

 

            // ajax

            var xhr = new XMLHttpRequest();

            // ajax行配置

            xhr.open('post''http://localhost:3000/formData');

            // ajax

            xhr.send(formData);

            // xhr象下面的onload事件

            xhr.onload = function () {

                // http状态码进行判

                if (xhr.status == 200) {

                    console.log(xhr.responseText);

                }

            }

 

            // 建空的表单对

            var f = new FormData();

            f.append('sex''');

            console.log(f.get('sex'));

        }

    </script>

</body>

</html>

3.4 FormData 二进制文件上传

图片,视频,音频文件

<input type="file" id="file"/> // 准备文件选择控件,用户选择文件后,我们要提交到服务器

 

// 获取文件

var file = document.getElementById('file')

// 当用户选择文件的时候触发

 file.onchange = function () {

     // 创建空表单对象:存用户选择的文件

     var formData = new FormData();

     // 将用户选择的二进制文件追加到表单对象中

// files属性 是文件的集合,哪怕你只选了一个文件,他也是一个集合;默认input选择文件控件 只能选择一个文件

     formData.append('attrName=数据的属性名称,后端开发人员定义', this.files[0]=具体要追加的数据,用户选择的文件,存在文件选择控件中的 files属性中);

     // 配置ajax对象,请求方式必须为post

     xhr.open('post', 'www.example.com');

     xhr.send(formData);

 }

3.5 FormData 文件上传进度展示

// 当用户选择文件的时候

 file.onchange = function () {

     // 文件上传过程中持续触发onprogress事件; upload对象下有一个 onprogress属性

     xhr.upload.onprogress = function (ev) {

         // 当前上传文件大小/文件总大小 再将结果转换为百分数

         // 将结果赋值给进度条的宽度属性

         bar.style.width = (ev.loaded / ev.total) * 100 + '%';

     }

 }

3.6 FormData 文件上传图片即时预览

在我们将图片上传到服务器端以后,服务器端通常都会将 图片地址做为响应数据传递到客户端,!!客户端可以从响应数据中获取图片地址,然后将图片再显示在页面中。

实际上node中做过图片及时预览功能,但是当时使用的是H5中的文件对象fileread实现的,但是有个问题,在不支持H5浏览器中,这个功能不好使

xhr.onload = function () {

     var result = JSON.parse(xhr.responseText);

     var img = document.createElement('img');

     img.src = result.src;

     img.onload = function () {

         document.body.appendChild(this);

     }

 }

 

App.js

// 实现文件上的路

app.post('/upload', (reqres=> {

    // formidable解析

    const form = new formidable.IncomingForm();

    // 置客端上文件的存

    form.uploadDir = path.join(__dirname'public''uploads');

    // 保留上文件的后名字

    form.keepExtensions = true;

    // 解析客传递过来FormData

    form.parse(req, (errfieldsfiles=> {

        // 传递过来的文件地址响应到客

        res.send({

            path: files.attrName.path.split('public')[1]

        });

    });

});

 

<!DOCTYPE html>

<html lang="en">

<head>

    <meta charset="UTF-8">

    <title>Document</title>

    <link rel="stylesheet" href="/assets/bootstrap/dist/css/bootstrap.min.css">

    <style type="text/css">

        .container {

            padding-top60px;

        }

        .padding {

            padding5px 0 20px 0;

        }

    </style>

</head>

<body>

    <div class="container">

        <div class="form-group">

            <label>请选择文件</label>

            <input type="file" id="file">

            <div class="padding" id="box">

                <!--<img src="" class="img-rounded img-responsive">-->

            </div>

            <div class="progress">

                <div class="progress-bar" style="width: 0%;" id="bar">0%</div>

            </div>

        </div>

    </div>

    <script type="text/javascript">

        // 1取文件选择控件

        var file = document.getElementById('file');

        // 元素

        var bar = document.getElementById('bar');

        // 片容器

        var box = document.getElementById('box');

 

        // 2文件选择控件添加onchanges事件 在用户选择文件时触发

        file.onchange = function () {

            // 2.1 建空的formData单对象:存用户选择的文件

            var formData = new FormData();

            // 2.2 户选择的文件追加到formData单对象中

            formData.append('attrName'this.files[0]);

            // 2.3 ajax象,Ajax

            var xhr = new XMLHttpRequest();

            // 2.4 ajax行配置xhr.open()只有post方式可以 行文件上

            //     upload路由 app.js 中要

            xhr.open('post''http://localhost:3000/upload');

            // 在文件上程中持续触发

            xhr.upload.onprogress = function (ev) {

                // ev.loaded 文件已了多少

                // ev.total  文件的大小

                var result = (ev.loaded / ev.total) * 100 + '%';

                // 

                bar.style.width = result;

                // 百分比示在

                bar.innerHTML = result;

            }

            // 2.5 ajax求,传递到服器端

            xhr.send(formData);

            // 2.6 听服器端响应给端的

            xhr.onload = function () {

                // 1)如果服器端返回的http状态码为200求是成功的

                if (xhr.status == 200) {

                    // 2器端返回的示在控制台中,客端代里截至完成了,

                    //      要接受这个文件,如何接受客传来的二制文件呢?

                    var result = JSON.parse(xhr.responseText);

                    // 3动态创img标签:直接获取设置src属性,用户体验不好,用户可以看到图片上传过程

                    var img = document.createElement('img');

                    // 4给图标签设src

                    img.src = result.path;

                    // 5当图片加完成以后,将图示在面中

                    img.onload = function () {

                        box.appendChild(img);

                    }

                }

            }

            

        }

    </script>

</body>

</html>

 

4.同源政策

4.1 Ajax请求限制

Ajax 只能向自己的服务器发送请求

比如现在有一个A网站、有一个B网站,A网站中的 HTML 文件只能向A网站服务器中发送 Ajax 请求,B网站中的 HTML 文件只能向 B 网站中发送 Ajax 请求

但是 A 网站是不能向 B 网站发送 Ajax请求的,同理,B 网站也不能向 A 网站发送 Ajax请求。

比如获取天气信息,只能请求国家气象局

如何解决呢?

为什么只能向自己的服务器发送请求呢?- 是因为有同源政策的限制

4.2 什么是同源

相同的来源,来自同一个地方;

如果两个页面拥有相同的协议、域名和端口那么这两个页面就属于同一个源,其中只要有一个不相同,就是不同源。没有端口,默认80

http://www.example.com/dir/page.html

http://www.example.com/dir2/other.html :同源

http://example.com/dir/other.html:不同源(域名不同)

http://v2.www.example.com/dir/other.html:不同源(域名不同)

http://www.example.com:81/dir/other.html:不同源(端口不同)

https://www.example.com/dir/page.html:不同源(协议不同)

4.3 同源政策的目的

同源政策是 为了保证用户信息的安全,防止恶意的网站窃取数据

最初的同源政策是指 A 网站在客户端设置的 CookieB网站是不能访问的。比如A是银行,用户登录以后,A网站在用户的机器上设置了一个 cookie 包含了一些隐私信息,比如存款总额,当用户离开A网站,访问B网站,如果没有同源限制,B网站就可以访问A网站的cookie,用户的隐私就被泄露了

随着互联网的发展,同源政策也越来越严格,在不同源的情况下,其中有一项规定 就是Ajax技术 无法向 非同源地址 发送Ajax 请求,如果请求,浏览器就会报错,并且给出提示。但实际上,请求可以发出去,只不过是浏览器拒绝接受服务器端的返回结果,所以请求还是失败的。

如何验证?用两个不同源的服务器

    <script type="text/javascript" src="/js/ajax.js"></script>

    <script type="text/javascript">

        ajax({

            url: 'http://localhost:3001/test',

            type: 'get',

            success: function (result) {

                console.log(result);

            }

        })

    </script>

4.4 使用 JSONP 解决同源限制问题

jsonp json with padding 的缩写,将json 数据填充到函数中,就是利用 script 标签的 src 属性的特性;它不属于 Ajax 请求但它可以模拟 Ajax 请求。这种解决方案 需要前后端人员配合完成

1. 将不同源的服务器端 请求地址写在 script 标签的 src 属性中, src 属性可以发送请求,也不受同源政策的影响,可以写非同源地址

<script src="www.example.com"></script>

<script src=“https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script>

2. 服务器端响应数据必须是一个函数的调用,真正要发送给客户端的数据需要作为函数调用的参数。当浏览器通过script标签将响应内容加载完成以后,会自动将响应内容作为script代码来执行;实际上,响应内容加载完成之后,会立即调用这个函数,因为加载过来的就是函数调用的代码,在服务器端,这个响应内容必须是字符串,包裹函数调用代码;如果不是字符串,就是真的函数调用,就会在服务器端执行了,我们目的是让他在客户端执行

在服务器端代码中,返回函数调用代码的同时,还要将客户端真正需要的数据写在函数调用实参的地方,函数在客户端被执行的时候,可以通过形参对应

函数在客户端被调用,客户端要先定义,才能被调用

const data = 'fn({name: "张三", age: "20"})';

res.send(data);

3. 在客户端全局作用域下定义函数 fn:写在script上边,函数调用才能找到这个函数的定义部分;服务器在返回函数调用的时候,已经将真正的数据作为函数的实参了,可以写一个形参可以和形参对应了

function fn (data) { }

4. fn 函数内部对服务器端返回的数据进行处理

function fn (data) { console.log(data); }

<!DOCTYPE html>

<html lang="en">

<head>

    <meta charset="UTF-8">

    <title>Document</title>

</head>

<body>

    <script>

        //2,函

        function fn (data) {

            console.log('端的fn用了')

            console.log(data); // zhangsan

        }

    </script>

    <!-- 1. 第一步 非同源服器端的求地址script标签src性中 

    这个请求地址部,返回一数调用的代=script求地址里的容以后,

    容是一数调用代,加之后,函数会被立即用,

    所以在客端要提前准的定部分,定在全局作用域下和script的上,才能找到

    -->

    <script src="http://localhost:3001/test"></script>

</body>

</html>

 

// 2

app.get('/test', (reqres=> {

    const result = 'fn({name: ""})';

    res.send(result);

});

 

4.5 JSONP 代码优化

  1. 客户端需要将函数名称 传递到服务器端。
  2. 将 script 请求的发送变成动态请求:想发送请求的时候,动态创建script标准,在追加到页面中/ 比如点击按钮发送请求

<!DOCTYPE html>

<html lang="en">

<head>

    <meta charset="UTF-8">

    <title>Document</title>

</head>

<body>

    <button id="btn">点我</button>

    <script>

        function fn2 (data) {

            console.log('端的fn用了')

            console.log(data);

        }

    </script>

    <script type="text/javascript">

        // 1取按

        var btn = document.getElementById('btn');

        // 2添加点事件

        btn.onclick = function () {

            // 3script标签

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

            // 4src

            script.src = 'http://localhost:3001/better?callback=fn2';

            // 5script标签追加到面中 document.body性再appendChild

            document.body.appendChild(script);

            // 6script标签添加onload事件,body中的script标签删除掉

            script.onload = function () {

                document.body.removeChild(script);

            }

        }

    </script>

</body>

</html>

  1. )封装 jsonp 函数,方便请求发送。
  2. )服务器端代码优化之 res.jsonp 方法。

【问题1jsonp函数用于发送请求,但是再函数外部其他地方,还要定义fn2函数用于接受服务器返回的数据;=发送一个请求,用两个函数,两个函数还是独立的,就打破了jsonp函数的封装性;不能一眼就看出那个请求和那个函数是关联的,如果可以像Ajax的处理请求结果的函数变成success函数一样,函数的封装性就比较好了

【问题2在真实的项目中,要发送很多请求,每个请求都要对应一个自己函数,处理服务器返回结果,为很多请求函数起名字也很麻烦。比如每个按钮对应的函数名字不一样,如果一样,后边就会覆盖前边;使用随机命名

<!DOCTYPE html>

<html lang="en">

<head>

    <meta charset="UTF-8">

    <title>Document</title>

</head>

<body>

    <button id="btn1">点我</button>

    <button id="btn2">点我</button>

    <script type="text/javascript">

        // 取按

        var btn1 = document.getElementById('btn1');

        var btn2 = document.getElementById('btn2');

        // 添加点事件

        btn1.onclick = function () {

            jsonp({

                // 求地址

                url: 'http://localhost:3001/better',

                data: {

                    name: 'lisi',

                    age: 30

                },

                success: function (data) {

                    console.log(123)

                    console.log(data)

                }

            })

        }

 

        btn2.onclick = function () {

            jsonp({

                // 求地址

                url: 'http://localhost:3001/better',

                // 问题1:已不是全局函了?服器返回函数调用,找不到,要把它变成全局函 / window象?

                // 问题2成匿名函

                success: function (data) {

                    console.log(456789)

                    console.log(data)

                }

            })

        }

 

        // 向非同源   

        function jsonp (options) {

            // 1动态创script标签

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

            // 接字符串的

            var params = '';

 

            for (var attr in options.data) {

                params += '&' + attr + '=' + options.data[attr];

            }

            

            // myJsonp0124741

            var fnName = 'myJsonp' + Math.random().toString().replace('.''');

 

            // 不是一全局函了,我要想将它变成全局函 .是不能跟量的

            window[fnName] = options.success;

            // 2script标签添加src性:求地址 只有在求,jsonp,才能知道

            script.src = options.url + '?callback=' + fnName + params;

            // script标签追加到面中

            document.body.appendChild(script);

            // script标签添加onload事件

            script.onload = function () {

                document.body.removeChild(script);

            }

        }

    </script>

</body>

</html>

// 服务器端代码 app.js

app.get('/better', (reqres=> {

    // 接收客传递过来的函的名

    //const fnName = req.query.callback;

    // 称对应的函数调用代返回

    //const data = JSON.stringify({name: ""});

    //const result = fnName + '('+ data +')';

    // setTimeout(() => {

    //  res.send(result);

    // }, 1000)

 

    // jsonp 方法直接可以干上的事情,j接受客户端发来的数据,对象转为字符串

    res.jsonp({name: 'lisi'age: 20});

})

【案例】-获取腾讯天气

从腾讯网获取天气信息, 获取未来48小时,并展示到自己的网站中

腾讯天气: https://tianqi.qq.com/

网站内容:当前时间天气,未来48小时,未来7天的

观察网站腾讯网站是如何获取天气信息的?

F12,开发者工具 – network – 重新刷新浏览器 – 找到所有天气的请求 – 其实就是和common相关的 – 点击一个 右键 open in new tab –

09【Ajax 】第二部分:Ajax 编程扩展, 模板引擎,案例,FormData,同源政策

09【Ajax 】第二部分:Ajax 编程扩展, 模板引擎,案例,FormData,同源政策

返回的就是一个函数的调用,(函数的调用),对象作为参数,对象就是具体的天气信息,就是jsonp形式的服务器端返回值

09【Ajax 】第二部分:Ajax 编程扩展, 模板引擎,案例,FormData,同源政策

观察的域名:tianqi.qq.com/ wis.qq.com 是 非同源网站,就是通过jsonp 请求过来的

 

09【Ajax 】第二部分:Ajax 编程扩展, 模板引擎,案例,FormData,同源政策

09【Ajax 】第二部分:Ajax 编程扩展, 模板引擎,案例,FormData,同源政策

09【Ajax 】第二部分:Ajax 编程扩展, 模板引擎,案例,FormData,同源政策

 

<!DOCTYPE html>

<html lang="en">

<head>

    <meta charset="UTF-8">

    <title>使用jsonp腾讯信息</title>

    <link rel="stylesheet" href="/assets/bootstrap/dist/css/bootstrap.min.css">

    <style type="text/css">

        .container {

            padding-top60px;

        }

    </style>

</head>

<body>

    <div class="container">

        <table class="table table-striped table-hover" align="center" id="box"></table>

    </div>

    <!-- 封装好的 jsonp  -->

    <script src="/js/jsonp.js"></script>

    <script src="/js/template-web.js"></script>

    <script type="text/html" id="tpl">

        <!--2 模板的容就是tr -->

        <tr>

            <th>时间</th>

            <th></th>

            <th></th>

            <th></th>

            <th></th>

        </tr>

        <!-- 2.1  tr&td-  td-  找到模板地方,告模板引擎,据和 HTML字符串 怎么拼

        info 象下,存的又是一堆象;循的方式 -->

        {{each info}}

        <tr>

            <!-- 2.2 value.update_time 时间,但是时间20190304120000是一字符串需要理成更加容易阅读方式 

            【解】定个处时间日期的方法,方法要在模板中去用;在模板中暴漏一外部量,可以是一-->

            <td>{{dateFormat($value.update_time)}}</td>

            <td>{{$value.degree}}</td>

            <td>{{$value.weather}}</td>

            <td>{{$value.wind_direction}}</td>

            <td>{{$value.wind_power}}</td>

        </tr>

        {{/each}}

    </script>

    <script>

        // 2.3 table标签

        var box = document.getElementById('box');

 

        // 3.1 在模板中 return 返回什 面中就会显示什

        function dateFormat(date) {

            // console.log(data); 取到了时间 20190909098060 截取时间需要

            var year = date.substr(04);

            var month = date.substr(42);

            var day = date.substr(62);

            var hour = date.substr(82);

            var minute = date.substr(102);

            var seconds = date.substr(122);

            return year + '' + month + '' + day + '' + hour + '' + minute + '' + seconds + '';

        }

 

        // 3,向模板中放外部量,是一template.defaults.imports固定的

        template.defaults.imports.dateFormat = dateFormat;

 

        // 1,向服器端取天信息

        jsonp({

            // 1.1 求地址

            url: 'https://wis.qq.com/weather/common',  

            // 1.2 需要传递参数:在接口文中有

            data: {

                source: 'pc',

                weather_type: 'forecast_1h',

                // weather_type: 'forecast_1h|forecast_24h',

                province: '江省',

                city: '哈尔'

            },

            // 1.3 求成功后,会调这个传进来用模板引擎展示在面中 

            success: function (data) {

                // console.log(data); 求到的天信息 

                // id='tpl' 第二个参数为对象,info:具体的天信息-data.data.forecast_1h

                var html = template('tpl', {info: data.data.forecast_1h});

                // 2.4 console.log(html); 很多tr td 追加 table标签中,给它起一名字

                box.innerHTML = html;

                

            }

        })

    </script>

</body>

</html>

 

4.6 CORS 跨域资源共享

CORS:全称为 Cross-origin resource sharing,即跨域资源共享,非同源跨域共享,jsonp-是绕过了同源限制,发送的也不是Ajax请求;它允许浏览器向 跨域服务器发送 Ajax 请求,克服了 Ajax 只能同源使用的限制。

这种解决办法:主要是在服务器端做一些配置

跨域过程:当客户端向服务器发请求,如果浏览器检测这个请求时跨域的,会自动加 请求头 origin字段,字段的值就是当前的域名信息,当前网站的页面地址;

比如A 网站 B 网站发送请求,origin中存的就是A的域名信息,包含协议,域名,端口号,服务器根据字段的值决定是否同意这次请求,不管同意不同意都会给一个响应,如果服务器同意,就会在相应头加入一个字段 Access-Control-Allow-Origin,如果不同意,就不加这个字段;浏览器自动完成,不需要开发人员完成;这个字段存的是 客户端的信息,如果你的信息被存在它服务器中,你就可以访问;这个字段的值是客户端的源信息,或者*号代表所有的客户端允许访问这个服务器。

09【Ajax 】第二部分:Ajax 编程扩展, 模板引擎,案例,FormData,同源政策

origin: http://localhost:3000

Access-Control-Allow-Origin: 'http://localhost:3000'

Access-Control-Allow-Origin: '*'

Node 服务器端设置响应头示例代码:客户端-Ajax代码;客户端需要做的浏览器会自动做好;服务器-允许那些客户端访问?设置客户端通过那些请求方式访问服务器端?这两项信息设置在相应头中

app.use((req, res, next) => {

     res.header('Access-Control-Allow-Origin', '*');

     res.header('Access-Control-Allow-Methods', 'GET, POST');

     next();

 })

S1号服务器:点击按钮,向2号服务器发送请求

09【Ajax 】第二部分:Ajax 编程扩展, 模板引擎,案例,FormData,同源政策

09【Ajax 】第二部分:Ajax 编程扩展, 模板引擎,案例,FormData,同源政策

S2号服务器中app.js

app.get('/cross', (reqres=> {

    // 1.许哪些客访问

// res.header('Access-Control-Allow-Origin', 'http://localhost:3000')

    // // 2.端使用求方法访问

    // res.header('Access-Control-Allow-Methods', 'get,post')

 

    res.send('ok')

});

// 优化代码;真实的项目中需要在每个路由中设置这两项内容妈?可以使用

// 中间件 截所有对所有的请求设置这俩;所有路由最上边写上桑app.use (()=>{})

app.use((reqresnext=> {

    // 1.许哪些客访问

    // * 代表允所有的客访问

    // 注意:如果跨域求中涉及到cookie信息传递不可以* 比如是具体的域名信息

    res.header('Access-Control-Allow-Origin''http://localhost:3000')

    // 2.端使用求方法访问

    res.header('Access-Control-Allow-Methods''get,post')

    // 送跨域cookie信息

    res.header('Access-Control-Allow-Credentials'true);

    next(); // 请求往下继续写匹配

});

09【Ajax 】第二部分:Ajax 编程扩展, 模板引擎,案例,FormData,同源政策 09【Ajax 】第二部分:Ajax 编程扩展, 模板引擎,案例,FormData,同源政策

4.7 访问非同源数据 服务器端另一种解决方案

这种解决方案,也是绕过浏览器的同源政策;同源政策是浏览器给予Ajax技术的限制,服务器端是不存在同源政策限制。服务器开发语言,可以直接访问非同源网站的数据;

所以客户端想访问非同源网站数据时候,可以让自己服务器端去获取非同源网站的数据,将数据响应到自己客户端;这样就绕过了同源政策

09【Ajax 】第二部分:Ajax 编程扩展, 模板引擎,案例,FormData,同源政策

用 1号网站的客户端 访问 1号服务器;1号网站服务器 访问 2号服务器,获取2号服务器的数据;响应给1号网站的客户端

09【Ajax 】第二部分:Ajax 编程扩展, 模板引擎,案例,FormData,同源政策

1号网站的服务器端app.js

09【Ajax 】第二部分:Ajax 编程扩展, 模板引擎,案例,FormData,同源政策  

4.8 cookie复习

当客户端向服务器发送请求的时候,会携带cookie,用以证明自己的身份,正常不跨域请求,这是没有问题的,但是跨域 cookie不会被发送问题;

但是现在有需求,比如有两个服务器都是自己的,想实现跨域登录功能, 就需要cookie技术;但是 因为是跨域发送请求,cookie不会发送到服务器;就无法实现登录功能?

09【Ajax 】第二部分:Ajax 编程扩展, 模板引擎,案例,FormData,同源政策

4.9 withCredentials属性

在使用Ajax技术发送跨域请求时,默认情况下不会在请求中携带cookie信息。Ajax下的一个属性,

withCredentials:指定在涉及到跨域请求时,是否携带cookie信息,默认值为false

Access-Control-Allow-Credentials:true 允许客户端发送请求时携带cookie,在响应头中设置

<!DOCTYPE html>

<html lang="en">

<head>

    <meta charset="UTF-8">

    <title>实现跨域功能</title>

    <link rel="stylesheet" href="/assets/bootstrap/dist/css/bootstrap.min.css">

    <style type="text/css">

        .container {

            padding-top60px;

        }

    </style>

</head>

<body>

    <div class="container">

        <form id="loginForm">

            <div class="form-group">

                <label></label>

                <input type="text" name="username" class="form-control" placeholder="请输入用">

            </div>

            <div class="form-group">

                <label></label>

                <input type="password" name="password" class="form-control" placeholder="请输入用密">

            </div>

            <input type="button" class="btn btn-default" value="" id="loginBtn">

            <input type="button" class="btn btn-default" value="检测录状态" id="checkLogin">

        </form>

    </div>

    <script type="text/javascript">

        // 取登

        var loginBtn = document.getElementById('loginBtn');

        // 检测录状态

        var checkLogin = document.getElementById('checkLogin');

        // 取登

        var loginForm = document.getElementById('loginForm');

        // 添加点事件

        loginBtn.onclick = function () {

            // 户填写容通jsonp提交到服

            // html单转换为formData单对

            var formData = new FormData(loginForm);

            // ajax

            var xhr = new XMLHttpRequest();

            // ajax行配置

            xhr.open('post''http://localhost:3001/login');

            // 当发送跨域,携cookie信息

            xhr.withCredentials = true;

            // 并传递请参数

            xhr.send(formData);

            // 听服器端予的响应内

            xhr.onload = function () {

                console.log(xhr.responseText);

            }

        }

 

        // 当检测户状态被点击时

        checkLogin.onclick = function () {

            // ajax

            var xhr = new XMLHttpRequest();

            // ajax行配置

            xhr.open('get''http://localhost:3001/checkLogin');

            // 当发送跨域,携cookie信息

            xhr.withCredentials = true;

            // 并传递请参数

            xhr.send();

            // 听服器端予的响应内

            xhr.onload = function () {

                console.log(xhr.responseText);

            }

        }

    </script>

</body>

</html>

app.use((reqresnext=> {

    // 1.许哪些客访问

    // * 代表允所有的客访问

    // 注意:如果跨域求中涉及到cookie信息传递不可以* 比如是具体的域名信息

    res.header('Access-Control-Allow-Origin''http://localhost:3000')

    // 2.端使用求方法访问

    res.header('Access-Control-Allow-Methods''get,post')

    // 送跨域cookie信息

    res.header('Access-Control-Allow-Credentials'true);

    next();

});

app.post('/login', (reqres=> {

    // 建表解析

    var form = formidable.IncomingForm();

    // 解析表

    form.parse(req, (errfieldsfile=> {

        // 接收客传递过来的用名和密

        const { usernamepassword } = fields;

        // 名密

        if (username == 'itheima' && password == '123456') {

            // session

            req.session.isLogin = true;

            res.send({message: '成功'});

        } else {

            res.send({message: '名或密码错误'});

        }

    })

});

 

app.get('/checkLogin', (reqres=> {

    // 是否于登录状态

    if (req.session.isLogin) {

        res.send({message: '于登录状态'})

    } else {

        res.send({message: '于未登录状态'})

    }

});

09【Ajax 】第二部分:Ajax 编程扩展, 模板引擎,案例,FormData,同源政策

 

相关文章: