- HTTP 超文本传输协议
- 发送一个请求查询用户日志记录
- 请求
- 响应
- 请求方式有哪些?
- 响应码有哪些?
- 客户端请求后,服务器响应携带的 https 证书
- 常用加密算法
- 快速搭建 Vue 普通 H5 项目页面的网络请求
- JS 变量修饰符
- 函数 Function
- Object 对象
- 对象的定义
- Ajax 请求
- Axios 框架
- Vue Cli 脚手架项目请求模块的搭建
- 基础安装环境
- package.json 配置
- 配置 main.js
- 请求 Demo 示例
- 模块之间的引用和导出
- H5 和 App 原生交互
- 客户端发 syn 询问给服务器。
- 服务器回应询问 syn,并发送一个指令 ack 客户端。
- 客户端回 ack 服务器。 正式连接成功后开始客户端请求 Http 报文,服务器响应报文。
:method: POST:scheme: https:authority: vendor-api-prod.gaoying.com:path: /customer/logs/Accept: application/json, text/plain, */*Content-Type: application/x-www-form-urlencoded //表单提交方式Origin: http://h5-vendor-dev.gaoying.comContent-Length: 236Accept-Language: zh-cnHost: vendor-api-dev.gaoying.comUser-Agent: Mozilla/5.0 (iPhone; CPU iPhone OS 13_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148Referer: http://h5-vendor-dev.gaoying.com/page/customerMain.html?customerId=172821&userId=15243265&token=41cadcb70eed35378a92379871a51181Accept-Encoding: gzip, deflate, brConnection: keep-alive
响应
status: 200 Access-Control-Allow-Origin: * Content-Type: application/json;charset=UTF-8 //json 响应格式 Date: Fri, 27 Dec 2019 05:58:18 GMT Server: Tengine
请求方式有哪些?
METHODS: [ 'ACL', 'BIND', 'CHECKOUT', 'CONNECT', 'COPY', 'DELETE', 'GET', 'HEAD', 'LINK', 'LOCK', 'M-SEARCH', 'MERGE', 'MKACTIVITY', 'MKCALENDAR', 'MKCOL', 'MOVE', 'NOTIFY', 'OPTIONS', 'PATCH', 'POST', 'PROPFIND', 'PROPPATCH', 'PURGE', 'PUT', 'REBIND', 'REPORT', 'SEARCH', 'SOURCE', 'SUBSCRIBE', 'TRACE', 'UNBIND', 'UNLINK', 'UNLOCK', 'UNSUBSCRIBE' ]
响应码有哪些?
STATUS_CODES: { '100': 'Continue', '101': 'Switching Protocols', '102': 'Processing', '103': 'Early Hints', '200': 'OK', '201': 'Created', '202': 'Accepted', '203': 'Non-Authoritative Information', '204': 'No Content', '205': 'Reset Content', '206': 'Partial Content', '207': 'Multi-Status', '208': 'Already Reported', '226': 'IM Used', '300': 'Multiple Choices', '301': 'Moved Permanently', '302': 'Found', '303': 'See Other', '304': 'Not Modified', '305': 'Use Proxy', '307': 'Temporary Redirect', '308': 'Permanent Redirect', '400': 'Bad Request', '401': 'Unauthorized', '402': 'Payment Required', '403': 'Forbidden', '404': 'Not Found', '405': 'Method Not Allowed', '406': 'Not Acceptable', '407': 'Proxy Authentication Required', '408': 'Request Timeout', '409': 'Conflict', '410': 'Gone', '411': 'Length Required', '412': 'Precondition Failed', '413': 'Payload Too Large', '414': 'URI Too Long', '415': 'Unsupported Media Type', '416': 'Range Not Satisfiable', '417': 'Expectation Failed', '418': "I'm a Teapot", '421': 'Misdirected Request', '422': 'Unprocessable Entity', '423': 'Locked', '424': 'Failed Dependency', '425': 'Unordered Collection', '426': 'Upgrade Required', '428': 'Precondition Required', '429': 'Too Many Requests', '431': 'Request Header Fields Too Large', '451': 'Unavailable For Legal Reasons', '500': 'Internal Server Error', '501': 'Not Implemented', '502': 'Bad Gateway', '503': 'Service Unavailable', '504': 'Gateway Timeout', '505': 'HTTP Version Not Supported', '506': 'Variant Also Negotiates', '507': 'Insufficient Storage', '508': 'Loop Detected', '509': 'Bandwidth Limit Exceeded', '510': 'Not Extended', '511': 'Network Authentication Required'}
客户端请求后,服务器响应携带的 https 证书
HTTPS在 HTTP 与 TCP 之间加入 SSL 层,一个加密/身份验证层,用于安全的 HTTP 数据传输。 它是一个 URI scheme(抽象标识符体系)。SSL 是安全套接层 。它的任务是负责在网络传输层基础上对网络连接进行数据加密。具有校验机制,配备身份证书。客户端利用公钥对数据加密,服务端收到加密数据后 对数据进行解密。
Https 服务器端口是 443, Https 公共密钥采用 RSA 算法加密,证书信息将在请求响应之前回复给客户端。客户端根据证书信息本地做一个安全校验,通过后再允许服务端响应返回数据,否则取消本次请求响应。签名算法:SHA-256 ECDSA
常用加密算法 对称加密- 单向散列函数MD5 是一种不可逆的信息摘要算法,严格来说不是加密。单向散列函数是一种不可逆的信息摘要算法,无法通过密文还原成明文(注意:是算法上不能实现),对于简单的 MD5 加密(这里的简单是指:明文长度短,且字符单一,并且进行 HASH 操作的时候没有进行加盐处理),是可以通过一些在线工具网站解密出来,实则是利用了彩虹表的技术。
- AES 加密 加密原理:字节代换、行位移、列混合(矩阵相乘:状态矩阵 和 固定矩阵相乘) 、轮钥加密:轮钥加密是将 128 位轮密钥 Ki 同状态矩阵中的数据进行逐位异或操作。
- DES 加密
- RSA 加密
在学习请求之前,需要掌握好 Javascript 语言。最基础的知识首先要了解和掌握变量修饰符,Function 和 Object 对象。
js 变量修饰符let 是局部变量,非常适合循环的时候。const 是只读变量, 初始化的时候就要赋值,且只能赋值一次。var 是全局变量,全局都可以用。
函数 Function 从上图我们看到有个名为 open 的函数,包含参数、调用者、长度、名字、以及 Proto 对象。该对象里面有 apply 、bind、 call 函数。还有一个 contructor 构造器。
Function 属性: length、name、prototype。
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 的用法:
//程序员的黄金年龄 18 ~ 35var checkProgramerAgeRange = function (value) { if (typeof value !== 'number') return false; else return value >= this.minimum && value { 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:qiustep2-1:异步请求处理耗时任务 2step2-1-result-event1:qiugaostep2-1-result-event2:qiugaoyingstep1-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 方法去捕捉异常和失败。
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 做第一件事情。 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 对象),可用来做一个类似批量处理之后汇总的业务。
testPromiseAll() { 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 实例只要有一个率先改变状态就会触发结果。
//打印结果: 兔子赢了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 项目。
基础安装环境npm install -g @vue/clivue create helloworld 方式创建项目也可以使用 GUI vue ui 来通过网页手动点击按钮操作来创建项目
package.json 配置
{ "name": "gaoying-cli", "version": "0.1.0", "private": true, "scripts": { "serve": "vue-cli-service serve", "build": "vue-cli-service build", "lint": "vue-cli-service lint" }, "dependencies": { "animate.css": "^3.7.2", "core-js": "^3.4.3", "vue": "^2.6.10", "vue-axios": "^2.1.5", "vue-router": "^3.1.3", "vuex": "^3.1.2", "weui.js": "^1.2.1" }, "devDependencies": { "@vue/cli-plugin-babel": "^4.1.0", "@vue/cli-plugin-router": "^4.1.1", "@vue/cli-plugin-vuex": "^4.1.1", "@vue/cli-service": "^4.1.0", "axios": "^0.19.0", "vue-template-compiler": "^2.6.10", "weui": "^2.1.3" }, "eslintConfig": { "root": true, "env": { "node": true }, "extends": [ "plugin:vue/essential", "eslint:recommended" ], "parserOptions": { "parser": "babel-eslint" } }, "browserslist": [ "> 1%", "last 2 versions" ]}
配置 main.js
import Vue from 'vue'import App from './App.vue'import router from './router'import store from './store'import axios from 'axios' //请求网络import VueAxios from 'vue-axios' import weui from 'weui.js' //weuiJsimport 'weui' //weui 样式import ymAPI from '@/assets/js/urlConfig.js' //Apiimport netManager from '@/assets/js/netManager.js' //请求基础参数拼接import ymNativeBridge from '@/assets/js/ymNativeBridge.js' //原生事件交互import animate from 'animate.css'const ymHttp = axios.create({ baseURL: 'https://vendor-api-prod.gaoying.com', timeout: 1000, transformRequest: [function(data) { // Do whatever you want to transform the data let ret = '' for (let it in data) { ret += encodeURIComponent(it) + '=' + encodeURIComponent(data[it]) + '&' } return ret }]});Vue.config.productionTip = falseVue.prototype.$weui = weuiVue.prototype.$ymAPI = ymAPIVue.prototype.$netManager = netManagerVue.prototype.$ymNativeBridge = ymNativeBridgeVue.use(VueAxios, ymHttp,animate)new Vue({ router, store, render: h => h(App)}).$mount('#app');
请求 Demo 示例
//和普通 h5 请求网络类似,唯一不同的就是通过挂载到 Vue 上的 axios ,可以通过 this.http 获取。this.netManager 也类似。
execBaseCustomerRequest: 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); });}
模块之间的引用和导出
import MD5 from './md5.js'export default { getRequestParams: function(params) { let userId = localStorage.getItem("userId"); let token = localStorage.getItem("token"); ...... }}//md5.js 文件中 var MD5 = function (string) { ......}module.exports = MD5//接口配置 urlConfig.js 文件中const ymAPI = { //客户信息 customerList: "/customer/list/", customerLogs: "/customer/logs/", customerCoupons: "/customer/coupons/", customerOrders: "/customer/orders/", customerDetail: "/customer/detail/"}module.exports = ymAPI
export 在 js 文件中可以有多个。
//testExport.jsexport 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 有多个的时候 ,导入必须用花括号括起来。
import {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。
//原生调用 appexport default { callApp:function(handlerMethod, parameters) { if (!window.WeixinJSBridge || !WeixinJSBridge.invoke) { var handlerInterface = 'YunMiaoNative'; var dic = { 'handlerInterface': handlerInterface, 'function': handlerMethod, //调用原生的指令 'parameters': parameters //传递的参数; }; if (/(iPhone|iPad|iPod|iOS)/i.test(navigator.userAgent)) { window.webkit.messageHandlers[handlerInterface].postMessage(dic); } else { //安卓 app.ymAppWebClick(); //dic } } else { //包含微信功能,比如可唤起小程序。 } }, //原生调用 app 并传递参数给 H5 callbackH5: function(handlerMethod, parameters, callbackMethod) { if (!window.WeixinJSBridge || !WeixinJSBridge.invoke) { var handlerInterface = 'YunMiaoH5'; var dic = { 'handlerInterface': handlerInterface, 'function': handlerMethod, //调用原生的指令 'parameters': parameters, //传递的参数; 'callbackMethod': callbackMethod //回调的函数 }; if (/(iPhone|iPad|iPod|iOS)/i.test(navigator.userAgent)) { window.webkit.messageHandlers[handlerInterface].postMessage(dic); } else { //安卓 app.ymAppWebClick(JSON.stringify(dic)); } } else { //包含微信功能,比如可唤起小程序。 } }}
阅读全文: http://gitbook.cn/gitchat/activity/5e146270eb69ea4eda349b34
您还可以下载 CSDN 旗下精品原创内容社区 GitChat App ,阅读更多 GitChat 专享技术内容哦。