个人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
/colorred默认不会携带cookie
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
}
代码下次在放