node、ajax(初级提高学习)


个人blog-1: 拾忆生活
个人blog-2: 极简-拾忆生活
欢迎大家来踩,同步更新


1.ajax状态码:

0:请求为初始化(未调用open())
1:请求已建立,未发送(未调用send())
2:请求已发送
3:请求处理中,已有部分数据可用
4:请求完成,可用获取并使用服务器的响应

2.获取ajax状态码

xhr.readyState

3.获取服务器端的响应(两种方法)

1.onload事件调用一次(推荐)
传递get请求参数.html

xhr.onload = function(){
                console.log(xhr.responseText);
            }

2.onreadystatechange事件调用多次
onreadystatechange监听readystate变化事件,当ajax状态码发送变化自动触发
获取服务器响应另一种方式.html

xhr.onreadystatechange=function(){
            console.log(xhr.readyState);//会变化,依次为2,3,4
            //对ajax状态码判断,如果==4即数据接收完成
            if(xhr.readyState==4){
                //响应台输出数据
                console.log(xhr.responseText);
            }
        }

4.响应台输出数据

console.log(xhr.responseText);

5.错误处理,获取http状态码

xhr.status

返回404错误,检查请求地址是否错误
返回500错误,如app.js中路由地址返回一个不存在的变量

app.get('/error',(req, res) => {
    console.log(abc);//返回不存在的变量,即500错误
    res.status(400).send('ERROR');
});
如果网络中断(通过Netw调成offline,变为断网)  
出现error处理.html:15 GET http://localhost:3000/error   net::ERR_INTERNET_DISCONNECTED
触发xhr.onerror事件

6.低版本IE缓存问题cache

解决保证每次移交参数不一样即可(用Math.random()),就不会从缓存中获取结果:
xhr.open(‘get’,‘http://localhost/cache?t=’+Math.random());

7.ajax封装

将请求代码封装到函数,发请求时调用函数

//获取响应头的数据:如text/html; charset=utf-8
xhr.getResponseHeader(‘Cont-Type’);
console.log(xhr.getResponseHeader(‘Content-Type’));

8.art-template模板引擎

单纯浏览器使用

1.直接下载template-web.js,在html中引入
<script src="../js/template-web.js"></script>

2.准备模板

<body>
    <script id="tp1" type="text/html">
        <div class="box"></div>
    </script>
</body>

3.告诉模板引擎将哪个模板(script的id名)和哪个数据进行拼接
var html=template(‘tp1’,{username:‘Lewis’,age:‘20’});

4.将拼接好的HTML字符串添加到页面中
document.getElementId(‘container’).innerHTML=html;

5.告诉模板引擎如何拼接

<body>
    <script id="tp1" type="text/html">
        <div class="box">{{username}}</div>
    </script>
</body>

数据:{{ data}} {{data.name}}
判断:{{if data}} {{data.name}} {{/if}}
一维遍历:{{each data}} {{$value}} {{/each}}
二维遍历:

   {{each data as value}}  //第一次遍历
        {{each value.more as item }}  //第二次遍历data.more
            {{item}} 
        {{/each}}
   {{/each}}

单纯浏览器使用

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>模板引擎</title>
    <script src="/js/template-web.js"/></script>
</head>
<body>

    <div id="container"></div>

    <!-- 准备art-template模板,id为模板引擎标识 -->
    <script id="tp1" type="text/html">
        <!-- {{}}告诉模板引擎如何拼接 -->
        <div class="box">{{username}}{{age}}</div>
    </script>

    <script type="text/javascript">
        //告诉模板引擎将哪个模板(script的id名)和哪个数据进行拼接
        //返回值就是拼接好的字符串
        var html = template('tp1',{username:'Lewis',age:20});
        console.log(html);
        //将拼接好的HTML字符串添加到页面中
        document.getElementId('container').innerHTML=html;
    </script>
</body>
</html>
用node.js

需要搭建服务器,读取整个页面数据,自动识别页面中的模板数据;通过响应回去的数据,将页面动态补充完整。

1.安装
npm install art-template
npm install http
npm install fs
npm install path
2.引入模块 const template = require(‘art-template’)
3.使用:template.render(‘模板’,{对象})方法
4.art-template.js引入template.render

let result = template.render('hello {{name}}',{
         name:'jack'
     });
     console.log(result);

5.运行node art-template.js
6.访问http://localhost:8080运行结果

服务器代码
art-template.js

const http = require('http');
const template = require('art-template');
const fs = require('fs');
const path = require('path');

http.createServer(function (req,res) {
    //读取页面文件
    fs.readFile(path.join(__dirname,"template.html"),function (err,data) {
        if(err)
            throw err;
       // 读取数据文件
        fs.readFile(path.join(__dirname,"template-data.json"),function (err,files) {
            if(err)
                throw err;

            let rest = template.render(data.toString(), {
                title: "个人信息",
                data: JSON.parse(files)
            });
            console.log(JSON.parse(files));
            res.end(rest);
        })
    })
}).listen(8080,function () {
    console.log("http://localhost:8080");
});

2.文件内容
template.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>{{title}}</title>
</head>
<body>
   // data 后面 value  代表每一项 ,index 为下标
   {{each data as value  index}}
    <p>hello , i am {{value.name}}</p>
    <p>i am {{value.age}} years old</p>
    <p>i come from {{value.province}}</p>
    <!--遍历二维数组-->
    <p>i like
        {{each value.hobbies as i }} {{i}} ,{{/each}}
    </p>
    <br>
   {{/each}}
</body>
</html>

3.数据data.json文件

[
  {"name":"Jack",
  "age":20,
  "province":"河南省'",
  "hobbies":["eat","music","play"]
  },
  {"name":"Rose",
    "age":18,
    "province":"北京市'",
    "hobbies":["eat","sleep","watch TV"]
  },
  {"name":"Little fairy",
    "age":16,
    "province":"陕西省'",
    "hobbies":["eat","sleep","read book"]
  }]

9.验证邮箱地址唯一性

1.获取文本框并为其添加焦点事件
2.离开焦点时,检测用户输入的邮箱是否符合规则
3.如果不符合规则,给出提示信息
4.如果符合规则,向服务器发送请求,检测邮箱地址是否被注册
5.客户端根据服务器返回的结果实现在页面

注:
2由html的 emailInp.οnblur=function(){}执行
3和4点由app.js和html中ajax函数执行

10.搜索框内容自动提示

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

11.FormData对象(不能用于get请求,只能post请求)

1.将HTML表单映射成表单对象,自动将表单对象中的数据拼接成请求参数的格式
2.异步上传二进制文件(图像)

//用于FormData对象
const formidable = require(‘formidable’);

npm i formidable


//将html表单转换为表单对象  
var formData = new FormData(form);

//获取表单对象属性的值,name属性值
formData.get('key');

//设置表单对象的属性值(第一个参数是属性 即input的name值,第二个参数是属性值)
//如果设置的表单属性存在,将会覆盖属性原有的值
//如果设置的表单属性不存在,将会创建这个表单属性
formData.set('key','value');//如果name中没有key,则可以创建一个input的name=key

//删除表单对象中的属性值
//可用于删除用户输入的密码input的name=password
console.log(formData.delete('password'));

//添加一个空的表单对象
var f = new FormData();
//向表单对象中追加属性值
//添加一个input的name=age的属性
f.append('age',10);
console.log(f.get('age'));


set和append区别:
在属性名已存在的情况下,set会覆盖已有属性名的值,append会保留已有属性名和它的值

12.同源

同源:两个页面有相同的协议(http和https不同)、域名、端口,有一个不同就是不同源
a网站的cookie,b网站不可访问

一个文件夹3000,一个文件夹3001,模拟不同源的情况

npm init -y
npm i express
npm i path
npm i nodemon

使用jsonp解决,不属于ajax请求,但可以模拟ajax请求

1.将不同源的服务器端请求地址写在script标签的src属性中

3000的html

<script>
    function fn(data){
        console.log('客户端的fn函数被调用');
        console.log(data);
    }
</script>
<!-- 1.将不同源的服务器端请求地址写在script标签的src属性中 -->
<script src="http://localhost:3001/test"></script>

2.服务器端响应数据必须是一个函数的调用

真正要发送给客户端的数据要作为函数调用的参数

3001的app.js
app.get('/test',(req,res)=>{
    const result = 'fn()';
    res.send(result);
})

app.get('/test',(req,res)=>{
    const data = 'fn({name:"张三",age:"20"})';
    res.send(data);
})

3.在客户端全局作用域下定义函数fn

3000的html
当script标签加载服务器的响应内容后,会直接调用这个函数,
function fn(data){ }

4.在发你函数内部对服务器返回的函数进行处理

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

客户端将函数名称传递到服务器端
将script请求的发送变成动态请求

3000的html

<button id="btn">点我发送请求</button>
    <script>
        //函数定义在全局作用域中
        function fn(data){
            console.log('客户端的fn函数被调用');
            console.log(data);
        }
        function fn2(data){
            console.log('客户端的fn2函数被调用');
            console.log(data);
        }
    </script>
    <!-- 1.将不同源的服务器端请求地址写在script标签的src属性中 -->
    <!-- 这个是立即发送 -->
    <script src="http://localhost:3001/test"></script>
    <!-- <script src="http://localhost:3001/test2?callback=fn2"></script>这个是立即发送,不是动态标签 -->
    <script>
        var btn = document.getElementById('btn');
        btn.onclick = function(){
            //创建script标签
            var script = document.createElement('script');
            //设置src地址属性,客户端用callback函数回调传递给服务器函数的名字
            script.src = 'http://localhost:3001/test2?callback=fn2';
            //将script标签追加到页面中
            document.body.appendChild(script);
            //将纳入加载完成后,将script标签删除
            script.onload = function(){
                document.body.removeChild(script);
            }
        }
    </script>

3001的app.js

//立即发送
app.get('/test',(req,res)=>{
    
    const data = 'fn({name:"张三",age:"20"})';
    res.send(data);
})

//非立即发送
app.get('/test2',(req,res)=>{
    //接受客户端传递回来的函数名称
    const fnName = req.query.callback;
    //将函数名称对应的函数调用代码返回给客户端
    const data = fnName+'({name:"张三",age:"20"})';
    res.send(data);
})
5.将jsonp函数封装(get请求)

3000的html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>jsonp封装</title>
</head>
<body>
    <button id="btn1">点我发送请求</button>
    <button id="btn2">点我发送请求</button>
    <script>
        //这里没有调用到这个函数名
        function fn3(data){
            console.log('客户端的fn2函数被调用');
            console.log(data);
        }
    </script>



    <script>
        var btn1 =document.getElementById('btn1');
        var btn2 =document.getElementById('btn2');
        btn1.onclick = function(){
        //调用封装好的jsonp函数
        jsonp({
            //请求地址
            //把?callback=fn3挂载到封装函数中处理
            url:'http://localhost:3001/fengzhuang',
            data:{
                name:'hhh',
                age:5
            },
            success:function(data){
                console.log('success函数1');
                console.log(data);
            }
        })
        }
        btn2.onclick = function(){
        //调用封装好的jsonp函数
        jsonp({
            //请求地址
            //把?callback=fn3挂载到封装函数中处理
            url:'http://localhost:3001/fengzhuang',
            data:{
                name:'eee',
                age:15
            },
            success:function(data){
                console.log('success函数2');
                console.log(data);
            }
        })
        }
        //封装jsonp函数
        function jsonp(options){
            //动态创建script标签
            var script = document.createElement('script');

            //拼接字符串变量
            var params ='';
            //遍历拼接拼接上success函数中的data属性和属性值
            for(var attr in options.data){
                params +='&' + attr + '=' + options.data[attr];
            }

            //此处处理fn函数,因为不是全局函数,所以用到window对象
            //把fn这个函数名看成window对象的属性,写success函数
            //为避免每次调用的函数名重复:
            //先随机生成一个数:0.14256
            //转换成:函数名字14256
            var fnName = 'jsonp'+ Math.random().toString().replace('.','');
            window[fnName] = options.success;
            //拼接函数名字、拼接上success函数中的data属性和属性值
            script.src = options.url + '?callback='+fnName + params;
            //将script标签追加到页面中
            document.body.appendChild(script);
            //将纳入加载完成后,将script标签删除
            script.onload = function(){
                document.body.removeChild(script);
            }
        }
        
    </script>
</body>
</html>

3001的app.js

//jsonp封装(方法一)
// app.get('/fengzhuang',(req,res)=>{
//     //接受客户端传递回来的函数名称
//     const fnName = req.query.callback;
//     //将json对象转换为字符串(数据库的信息)
//     var data =JSON.parse({name:"李四",age:21})
//     //将函数名称对应的函数调用代码返回给客户端
//     const result = fnName + '('+ data +')';
//     setTimeout(()=>{
//         res.send(result);
//     },1000);
    
// });

//jsonp封装(方法二)
app.get('/fengzhuang',(req,res)=>{
    res.jsonp({name:'lisi',age:'20'});
});

13.不同源策略二:CORS

CORS:跨域资源共享,克服ajax只能同源使用
允许浏览器向跨域服务器发送ajax请求

浏览器端给服务器端的请求头(origin):
origin:http://localhost:3000
服务器端给浏览器端的响应头(Access-Control_Access_Origin):
//1.允许哪些客户端访问我,‘’代表所有都可以访问
res.header(‘Access-Control-Allow-Origin’,’
’);
//2.允许客户端通过哪些方法访问我
res.header(‘Access-Control-Allow-Methods’,‘get,post’);

没有设置的后果:
Access to XMLHttpRequest at ‘http://localhost:3001/CORS?’ from origin ‘http://localhost:3000’ has been blocked by CORS policy: No ‘Access-Control-Allow-Origin’ header is present on the requested resource.

3301的服务器app.js

//用CORS 先拦截所有的客户端跨域请求
app.use((req,res,next)=>{
    //1.允许哪些客户端访问我,‘*’代表所有都可以访问
    res.header('Access-Control-Allow-Origin','*');
    //2.允许客户端通过哪些方法访问我
    res.header('Access-Control-Allow-Methods','get,post');
    //3.继续下一个请求,避免拦截时卡在这里
    next();
});

//这个通过中间件app.use先拦截所有请求
app.get('/CORS',(req,res)=>{
    res.send('访问成功');
});

3000的html

<body>
    <button id="btn">点我发送请求</button>
    <script src="./js/ajax.js"></script>

    <script>
        var btn = document.getElementById('btn');
        btn.onclick = function(){
            ajax({
                type:'get',
                url:'http:localhost:3001/CORS',
                success:function(data){
                    console.log(data);
                }
            })
        };
    </script>

</body>

14.不同源策略三:request模块(在本源的服务器访问不同源的服务器)

原理:
由a浏览器端请求到a服务器端,再由a服务器端请求到b服务器端
最后又b服务器端响应到a服务器端,再由a服务器端响应到a浏览器端

npm i request;

3000的app.js

···
//向其他服务器请求数据的模块
const request = require('request');
···
app.get('/require',(req,res)=>{
    request('http://localhost:3001/CORS',(err,response,body)=>{
        res.send(body);
    })
});

3001的app.js

//这个通过中间件app.use先拦截所有请求
app.get('/CORS',(req,res)=>{
    res.send('访问成功');
});


3000的html

<button id="btn">点我发送请求</button>
    <script src="/js/ajax封装.js"></script>



    <script>
        var btn = document.getElementById('btn');
        btn.onclick = function(){
            ajax({
                type:'get',
                url:'http://localhost:3001/require',
                success:function(data){
                    console.log(data);
                }
            })
        }
    </script>

15.不同源策略三:cookie

cookie原理:
客户端向服务器端请求数据,服务器端向客户端发送cookie(类似身份证),这次请求失败
客户端再用cookie向服务器端请求数据,服务器端响应,这次请求成功

ajax在发送跨域请求时 / c o l o r r e d 默 认 不 会 携 带 c o o k i e /color{red}默认不会携带cookie /colorredcookie
withCredentials:false
res.header(‘Access-Control-Allow-Credentials’,true);

session原理:
在服务器内存中开辟一块地址空间,专门存放每个客户端私有的数据,每个客户端根据cookie中保存的私有sessionId,可以获取到独属于自己的session数据。

区别:
session放在服务器端。当浏览器关闭就会清空。session时间不宜设置过长,否则大量占用服务器内存。
cookie适合长时间保存,在登出时被清除

检测用户登录状态:
1)用户密码登录时,在后台的req中记住session.
2)如果用户保存登录密码,则记住cookie,否则把当前用户的cookie设置为空;
3)每次用户需要向后台进行请求时,进行状态检验:
session是否存在?

  • 若存在,则继续进行请求操作,并将session的有效时间重新设置一次;
  • 若不存在,则判断cookie是否存在?
    • 若存在,使用该cookie完成自动登录,即完成了一次
    • 若不存在,则页面重定向到登录页面。

3001的app.js
npm install formidable
npm install express-session
npm i cookie-parser
npm i express-session
express、path

我没有做成功~~~

16.腾讯天气api(用第一种不同源策略jsonp)

请求地址:https://wis.qq.com/weather/common
参数名称            含义
source              请求类型: pc/wx
province            省份:广东
city                城市:深圳
county              县区:龙岗区
callback            回调函数 不传直接返回json
weather_type        observe 当前天气
weather_type        forecast_1h
weather_type        forecast_24h
weather_type        index 穿衣,舒适度等
weather_type        alarm 预警
weather_type        tips 天气介绍
weather_type        air 空气质量
weather_type        rise 日出
weather_type        查询类型,多个|分隔

返回值:
{
    "data": {
        //逐时天气7天(0-7)
        "forecast_24h": {
            "0": {
                "degree":"x",//温度
                "updata_time":"20200313000000",//时间
                "weather":"晴",//天气名称
                "weather_code":"00",//天气码
                "weather_short":"晴",//天气简要名称
                "wind_direction":"南风",//风向
                "wind_power":"3",//风力
                }
        }
    },
    "message": "OK",
    "status": 200
}

代码下次在放

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值