HTTP超文本传输协议。
TCP 三次握手。
1、客户端 发syn询问 给 服务器
2、服务器 回应询问syn,并发送一个指令ack 客户端
3、客户端 回 ack 服务器。 正式连接成功。 开始客户端请求Http报文 ,服务器响应报文。
四次挥手过程
发送一个请求查询用户日志记录
请求
1 | :method: POST |
响应
1 | status: 200 |
请求方式有哪些?
1 | METHODS: [ |
响应码有哪些?
1 | STATUS_CODES: { |
客户端请求后,服务器响应携带的https证书
HTTPS:
在HTTP与TCP之间 加入SSL层,一个加密/身份验证层,用于安全的HTTP数据传输。 它是一个URI scheme(抽象标识符体系)。
SSL : 安全套接层 , 在网络传输层基础上对网络连接进行数据加密; 具有校验机制,配备身份证书。
客户端利用公钥对数据加密,服务端收到加密数据后 对数据进行解密;
Https 服务器端口是443, Https 公共密钥采用 RSA算法加密, 证书信息将在请求响应之前回复给客户端。客户端根据证书信息 本地做一个安全校验,通过后再允许服务端响应返回数据,否则取消本次请求响应。
签名算法:SHA-256 ECDSA
常用加密算法
对称加密
- 单向散列函数
MD5 是一种 不可逆的信息摘要算法,严格来说不是加密。
单向散列函数是一种不可逆的信息摘要算法,无法通过密文还原成明文(注意:是算法上不能实现),对于简单的 MD5 加密(这里的简单是指:明文长度短,且字符单一,并且进行 HASH 操作的时候没有进行加盐处理),是可以通过一些在线工具网站解密出来,实则是利用了彩虹表的技术。 - AES 加密
加密原理: 字节代换,行位移,列混合:(矩阵相乘:状态矩阵 和 固定矩阵相乘) ,轮钥加密:轮钥加密是将128位轮密钥Ki同状态矩阵中的数据进行逐位异或操作 - DES 加密
非对称加密
- RSA 加密
快速搭建Vue 普通h5项目页面的网络请求
在学习请求之前,需要掌握好Javascript语言。最基础的知识首先要了解和掌握变量修饰符,Function 和 Object对象。
js 变量修饰符
let 是局部变量,非常适合循环的时候;
const 是只读变量, 初始化的时候就要赋值;只能赋值一次;
var 是全局变量,全局都可以用。
函数 Function
从上图我们看到有个名为open的函数,包含参数,调用者,长度,名字,以及 Proto 对象。该对象里面有 apply ,bind, call 函数。还有一个contructor构造器。
- Function属性: length,name,prototype
Function方法:
- Function.prototype.apply(), //调用一个函数并将其设置为提供的值。 可以将参数作为Array对象传递
- Function.prototype.bind(), //创建一个新函数,该新函数在调用时将其设置为提供的值,并在调用新函数时在提供的任何参数之前添加给定的参数序列。
- Function.prototype.call(), //调用一个函数并将其设置为提供的值。 可以按原样传递参数。
- Function.prototype.toString() //返回表示函数源代码的字符串。
//题外话,apply 和 bind 增强代码的扩展性,类似iOS 的category;
①动态改变this的指向,也就是this从callObject动态切换为thisArg。
②callObject.method.apply(thisArg,thisArray),可以将thisArray转化为arguments,传入到callObject.method内部。
我们通过以下代码来测试bind 的用法:1
2
3
4
5
6
7
8
9
10
11
12
13//程序员的黄金年龄 18 ~ 35
var checkProgramerAgeRange = function (value) {
if (typeof value !== 'number')
return false;
else
return value >= this.minimum && value <= this.maximum;
}
let programmerRange = { minimum: 18, maximum: 35 };
// 把函数内部的this修改为range对象,
let boundCheckProgramerAgeRange = checkProgramerAgeRange.bind(programmerRange);
console.log(boundCheckProgramerAgeRange(12));
Object 对象
Object 继承Function, 扩展了自己的许多方法。
Object 的属性构造器 Object.prototype
Object.assign() 将所有可枚举的自身属性的值从一个或多个源对象复制到目标对象。
Object.create() 用指定的原型对象和属性创建一个新对象。
Object.defineProperty() 定义一个property给指定对象
Object.defineProperties() 定义一个属性 给指定对象
Object.entries() 返回一个装有map的数组。
Object.getOwnPropertyNames() 得到这个对象自己的属性名
Object.getPrototypeOf() 得到指定类型的属性
Object.is() 比较对象
Object.keys() 字符窜属性
Object.values()
1 | let stuObj = {room:"english"}; |
对象的定义
传统方式定义一个对象
1 | function Person(name,age){ |
Class方式定义一个对象
1 | class Person{ |
类的本质是对象,对象继承Function; 所以introduce方法还是存储在prototype 公共空间中。操作类函数也可通过Person.prototype 去动态新增新的方法。另外要注意一点类的所有实列共享原型的prototype。1
2
3let student = new Person("qiugaoying",18);
let student2 = new Person("lihua",22);
console.log(student.__proto__ == student2.__proto__); //结果为true。 类的所有实列共享原型的prototype
Ajax 请求
通常,发起一个请求,需要传入基础参数,业务url, 业务参数,设置请求头,和响应方式。 接着对响应成功和失败的处理;
前端通常的请求方式有 表单提交,Ajax异步请求,Jquery也提供了ajax封装的快捷api。另外也有较新的框架Axios。
ajax 的出现是解决局部数据刷新的问题。可通过后台异步调用接口 实现页面局部刷新。浏览器原生有个XMLHttpRequest对象。
jQuery 出来之后,ajax的调用简化了好多
1 | $ajax({ |
Axios 框架
Axios 是一个基于 promise 的 HTTP 库,可以用在浏览器和 node.js 中. 我们来观察一下 在axios 的api 方法。
- 从图可以看出,有个默认属性中有个xmlHttpRequet网络适配器。
- 可设置基础baseURL , 以及请求头,请求超时等一些基础设置。
- 转换请求数据和响应数据,支持防御 XSRF。
- 提供了常用的get,post 等请求。自动转换 JSON 数据。还提供请求和响应的拦截器。
script标签引入axios 的js
1 | <script src="https://unpkg.com/axios/dist/axios.min.js"></script> |
封装基础参数,排序 加密等
对请求的基础参数做一个封装。 大部分请求都需要带上一些基础参数和userId,token 等字段。最后对所有字段key排序,最后转成Json 字符串再加密。以下为示例:
1 | const netManager = { |
axios实列发起一个请求示例
这里拿请求用户个人主页基础信息为样例,把下面方法放入 Vue 的 methods 中。 加载loading用到的是weiui.js.
以下可以实现一个分页加载的请求1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57var vm = new Vue({
el: '#PageContainer1',
data: {
//分页数据
pageNumber: 1,
pageSize: 10,
gyPageListStart: 0,
hasMoreDataFlag: false,
dataSource: [],
},
methods: {
execBaseCustomerRequest: function(url, listKey) {
var loading = null;
if (this.pageNumber == 1) {
loading = weui.loading('加载中');
}
let pageVue = this; //this在不同的作用域中指向的对象不同;临时存储vue对象
if (this.pageNumber == 1) {
this.gyPageListStart = 0;
}
http.post(url, netManager.getRequestParams({
customer_id: this.customerId,
start: this.gyPageListStart,
size: 10,
})).then(function(response) {
if (loading) {
loading.hide();
}
let dataDic = response.data;
if (dataDic.status == 1) {
var arr = pageVue.dataSource;
if (pageVue.pageNumber == 1) {
arr = [];
}
var dataArr = dataDic.data[listKey];
arr = arr.concat(dataArr);
pageVue.gyPageListStart = dataDic.data.start;
vm.$data.hasMoreDataFlag = (dataDic.data.more == 1);
vm.$data.dataSource = arr;
}
setTimeout(function() {
pageVue.requestLoadingFinished = true;
}, 800);
//重置加载完成的状态;
}).catch(function(error) {
console.log(error);
});
}
}
});
其他: url 通常会放到一个全局文件中配置1
2
3
4
5
6
7const gaoyingAPI = {
customerList: "/customer/list/",
customerLogs: "/customer/logs/",
customerCoupons: "/customer/coupons/",
customerOrders: "/customer/orders/",
customerDetail: "/customer/detail/"
}
Promise 用法简要讲解
从上文中,我们看到http发送post 方法请求之后,通过promise语法 then的回调监听响应结果,通过catch方法 来捕捉异常错误处理。ES6 就支持了Promise的用法。
Promise中文为承诺。有三种状态:pending(进行中)、fulfilled(已成功)、rejected(已失败)。 即状态一旦更改就不能再次改变赋值。这也是承诺的意义。
Promise实列通过.then方法或者.catch方法 返回一个新的Promise实例来实现链式调用。.then方法可以返回普通值或者一个新的promise。不设置返回值时,默认返回null。
Promise有很多用法,但什么情况下需要用到Promise呢? 在需要处理异步耗时任务的时候,可用Promise包装后进行返回。Promise用的时候会遇到很多种情况,Promise也提供了对应的解决方法。
- 当Promise.then方法返回一个新的Promise时候,下一级的then 将在 新的Promise then 执行 之后执行。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70//Promise then 嵌套 方式一
new Promise(resolve => {
console.log("step1:异步请求处理耗时任务");
setTimeout(() => {
resolve("qiu");
}, 1000);
}).then(value => {
//第一个接口请求成功拿到qiu
console.log("step1-result:" + value);
return new Promise(resolve => {
console.log("step2-1:异步请求处理耗时任务2");
setTimeout(() => {
resolve("qiugao");
}, 1000);
//触发第二个接口请求
}).then(value => {
//第二个接口请求成功,拿到id2 做第一件事情。
console.log("step2-1-result-event1:" + value);
return "qiugaoying";
}).then(value => {
//第二个接口请求成功,拿到id2 做第二件事情。
console.log("step2-1-result-event2:" + value);
return "hello, my name is qiugaoying";
});
}).then(value => {
//最后全部请求完成,触发汇总刷新。
console.log("step1-result:" + value);
});
/*
console输出结果:
step1:异步请求处理耗时任务
step1-result:qiu
step2-1:异步请求处理耗时任务2
step2-1-result-event1:qiugao
step2-1-result-event2:qiugaoying
step1-result:hello, my name is qiugaoying
*/
//Promise then 嵌套,方式二: 把then移到同一级展开。执行打印结果是一样的。
new Promise(resolve => {
console.log("step1:异步请求处理耗时任务");
setTimeout(() => {
resolve("qiu");
}, 1000);
}).then(value => {
//第一个接口请求成功拿到qiu
console.log("step1-result:" + value);
return new Promise(resolve => {
console.log("step2-1:异步请求处理耗时任务");
setTimeout(() => {
resolve("qiugao");
}, 1000);
//触发第二个接口请求
});
}).then(value => {
//第二个接口请求成功,拿到id2 做第一件事情。
console.log("step2-1-result-event1:" + value);
return "qiugaoying";
}).then(value => {
//第二个接口请求成功,拿到id2 做第二件事情。
console.log("step2-1-result-event2:" + value);
return "hello, my name is qiugaoying";
}).then(value => {
//最后全部请求完成,触发汇总刷新。
console.log("step1-result:" + value);
}); - then 方法提供两个参数,第二个参数可选。一个是名为resolve的成功回调 和 另一个名为reject 的失败回调。通常处理一个失败回调我们会用catch方法去捕捉异常和失败。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41new Promise(resolve => {
console.log("step1:异步请求处理耗时任务");
setTimeout(() => {
resolve("qiu");
}, 1000);
}).then(value => {
//第一个接口请求成功拿到qiu
console.log("step1-result:" + value);
return new Promise(resolve => {
console.log("step2-1:异步请求处理耗时任务");
setTimeout(() => {
resolve("qiugao");
}, 1000);
//触发第二个接口请求
});
}).then(value => {
//第二个接口请求成功,拿到id2 做第一件事情。
let hasError = true
if (hasError) {
throw new Error("step2-1-result-event1-error报异常");
//抛出异常 将不再继续执行then, 直接到catch异常;中途如果没有遇到catch 将直接到最后的catch.
} else {
console.log("step2-1-result-event1:" + value);
return "qiugaoying";
}
})
/*.catch(err => {
console.log("中途catchError会继续往下走:" + err);
return "qiugaoying"
//也会返回一个promise实例,并且是resolved状态,不会被最后一个catch 捕捉
})*/
.then(value => {
//第二个接口请求成功,拿到id2 做第二件事情。
console.log("step2-1-result-event2:" + value);
return "hello, my name is "+value;
}).then(value => {
//最后全部请求完成,触发汇总刷新。
console.log("step1-result:" + value);
}).catch(error => {
console.log("end error:" + error);
}); - finally 方法是最终执行的方法(无参) ,无论状态是什么,成功 or 失败 都会执行收尾。
Promise 还提供all 方法(接收一个数组,里面值可以是普通函数,或者Promise对象),可用来做一个类似批量处理之后汇总的业务。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70testPromiseAll() {
function washFood(){
console.log('做饭第一步:洗菜');
let hasError = false;
if(hasError){
return "发现了一只虫子!洗掉它。";
}else{
return '菜洗干净了。';
}
}
function cutFood() {
console.log('做饭第二步:切菜');
var p = new Promise(function (resolve, reject) { //做一些异步操作
setTimeout(function () {
let cutFoodHasError = true; //控制默契切菜时 是否发生异常
if(cutFoodHasError){
reject("呜呜~ 割到手了,流血!")
}else{
resolve('切好了菜。');
}
}, 1000);
})
/* 试试打开这里的注释
.catch(error=>{
console.log("切菜异常:"+error); //异常本身就是返回resolve状态,值是null
console.log("用创口贴止血,继续做菜。");
});
*/
return p;
}
function cooking() {
console.log('做饭第三步:炒菜');
var p = new Promise(function (resolve, reject) { //做一些异步操作
setTimeout(function () {
resolve('菜已做好!');
}, 2000);
});
return p;
}
//数组里,如果放Promise 一定要返回状态。
Promise.all([washFood(), cutFood(),cooking()])
.then((result) => {
console.log('上桌,吃饭了:'+result);
console.log(result);
}).catch(error=>{
console.log("菜没做成,出现了小事故:"+error);
})
/*
结果:
1. 当cutFoodHasError = true;打印如下结果:
菜没做成,出现了小事故:呜呜~ 割到手了,流血!
2. 当cutFoodHasError = true 且 cutFood方法里的Promise有异常捕捉时:
切菜异常:呜呜~ 割到手了,流血!
上桌,吃饭了:菜洗干净了!,,菜已做好
3. 当cutFoodHasError = false
上桌,吃饭了:菜洗好了。切好了菜。菜已做好!
*/
/*
Promise.all使用总结:
数组里可以是Promise对象,也可以是别的值,只有Promise会等待状态改变
当所有的子Promise都完成,该Promise完成,返回值是全部值得数组
有任何一个失败,该Promise失败,返回值是第一个先失败的子Promise结果
*/
},Promise 另外一个race 方法与all 不同的是,race 类似竞赛,参数中的Promise实例只要有一个率先改变状态就会触发结果。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
//打印结果: 兔子赢了
testPromiseRace() {
function rabbit() {
console.log('兔子选手');
var p = new Promise(function (resolve, reject) {
setTimeout(function () {
resolve('兔子赢了');
}, 1000);
}) .catch(error=>{
console.log("兔子跑步中出现异常:"+error);
});
return p;
}
function tortoise() {
console.log('乌龟选手');
var p = new Promise(function (resolve, reject) {
setTimeout(function () {
resolve('乌龟赢了');
}, 3000);
});
return p;
}
Promise.race([rabbit(),tortoise()])
.then((result) => {
console.log("比赛结果:"+result);
})
}
Vue Cli 脚手架项目请求模块的搭建
在vue的基础上,我们可以通过vue cli来管理我们的项目。vue cli 方式的优势在于模块之间可以很好地相互引用,通过package 包来管理配置相关的框架依赖。生态非常丰富,可轻松运用vue-router 来解决路由跳转等问题。
首先第一步是要创建一个 vue cli项目。
基础安装环境
1 | npm install -g @vue/cli |
package.json 配置
1 | { |
配置main.js
1 | import Vue from 'vue' |
请求Demo示例
//和普通h5 请求网络类似,唯一不同的就是通过挂载到Vue上的axios ,可以通过this.$http 取得。this.$netManager 也类似。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44execBaseCustomerRequest: function(url, listKey) {
var loading = null;
if (this.pageNumber == 1) {
loading = this.$weui.loading('加载中');
this.gyPageListStart = 0;
}
let pageVue = this; //this在不同的作用域中指向的对象不同;临时存储vue对象
this.$http.post(url, this.$netManager.getRequestParams({
customer_id: this.customerId,
start: this.gyPageListStart,
size: 10,
})).then(function(response) {
if (loading) {
loading.hide();
}
let dataDic = response.data;
if (dataDic.status == 1) {
var arr = pageVue.dataSource;
if (pageVue.pageNumber == 1) {
arr = [];
}
var dataArr = dataDic.data[listKey];
arr = arr.concat(dataArr);
pageVue.gyPageListStart = dataDic.data.start;
pageVue.hasMoreDataFlag = (dataDic.data.more == 1);
pageVue.dataSource = arr;
}else{
pageVue.$weui.topTips(dataDic.errorMsg);
}
setTimeout(function() {
pageVue.requestLoadingFinished = true;
}, 800);
//重置加载完成的状态;
}).catch(function(error) {
console.log(error);
});
}
模块之间的引用和导出
1 | import MD5 from './md5.js' |
export 在js文件中可以有多个.1
2
3
4
5
6
7
8//testExport.js
export const person = { name: "qiugaoying",sex:1, job:"software Programmer"}
export const addressInfo = {province:"广东省", city:"guangzhou"}
export const introduct = function(){
console.log("my name is qiugaoying");
}
export 有多个的时候 ,导入必须用花括号括起来.1
2import {person,addressInfo} from "../../utils/testExport.js"
import * as allExp from "../../utils/testExport.js" //加载全部export,取个别名
总结
- export default 只能导出一个对象。import 和 export 同一js文件中可以导入或导出多次。
- module.exports 和 exports 都是 node 端在用,两者指向同一内存块,可以导出变量 或 函数,对象。
- exports 变量是在模块的文件级作用域内可用的,且在模块执行之前赋值给 module.exports。
H5 和 App 原生交互
1 |
|