docs: 反爬虫之防重放策略

This commit is contained in:
杭城小刘
2020-02-25 21:21:00 +08:00
parent 47846f9af0
commit b0b7955c46
4 changed files with 77 additions and 35 deletions

View File

@@ -7,6 +7,8 @@
大道理谁都懂,但是按照我知道的情况,还是有非常多的人和公司在 Hybrid 这一块并没有做的很好,所以我将我的经验做一个总结,希望可以帮助广大开发者的技术选型有所帮助 大道理谁都懂,但是按照我知道的情况,还是有非常多的人和公司在 Hybrid 这一块并没有做的很好,所以我将我的经验做一个总结,希望可以帮助广大开发者的技术选型有所帮助
## Hybrid 的一个现状 ## Hybrid 的一个现状
可能早期都是 PC 端的网页开发随着移动互联网的发展iOS、Android 智能手机的普及,非常多的业务和场景都从 PC 端转移到移动端。开始有前端开发者为移动端开发网页。这样子早期资源打包到 Native App 中会造成应用包体积的增大。越来越多的业务开始用 H5 尝试,这样子难免会需要一个需要访问 Native 功能的地方,这样子可能早期就是懂点前端技术的 Native 开发者自己封装或者暴露 Native 能力给 JS 端,等业务较多的时候者样子很明显不现实,就需要专门的 Hybrid 团队做这个事情;量大了,就需要规矩,就需要规范。 可能早期都是 PC 端的网页开发随着移动互联网的发展iOS、Android 智能手机的普及,非常多的业务和场景都从 PC 端转移到移动端。开始有前端开发者为移动端开发网页。这样子早期资源打包到 Native App 中会造成应用包体积的增大。越来越多的业务开始用 H5 尝试,这样子难免会需要一个需要访问 Native 功能的地方,这样子可能早期就是懂点前端技术的 Native 开发者自己封装或者暴露 Native 能力给 JS 端,等业务较多的时候者样子很明显不现实,就需要专门的 Hybrid 团队做这个事情;量大了,就需要规矩,就需要规范。
@@ -23,9 +25,13 @@ Hybrid 在大量应用的时候就需要一定的规范,那么本文将讨论
- 资源缓存策略,白屏问题... - 资源缓存策略,白屏问题...
## Native 与前端分工 ## Native 与前端分工
在做 Hybird 架构设计之前我们需要分清 Native 与前端的界限。首先 Native 提供的是宿主环境,要合理利用 Native 提供的能力,要实现通用的 Hybrid 架构,站在大前端的视觉,我觉得需要考虑以下核心设计问题。 在做 Hybird 架构设计之前我们需要分清 Native 与前端的界限。首先 Native 提供的是宿主环境,要合理利用 Native 提供的能力,要实现通用的 Hybrid 架构,站在大前端的视觉,我觉得需要考虑以下核心设计问题。
### 交互设计 ### 交互设计
Hybrid 架构设计的第一要考虑的问题就是如何设计前端与 Native 的交互,如果这块设计不好会对后续的开发、前端框架的维护造成深远影响。并且这种影响是不可逆、积重难返。所以前期需要前端与 Native 好好配合、提供通用的接口。比如 Hybrid 架构设计的第一要考虑的问题就是如何设计前端与 Native 的交互,如果这块设计不好会对后续的开发、前端框架的维护造成深远影响。并且这种影响是不可逆、积重难返。所以前期需要前端与 Native 好好配合、提供通用的接口。比如
@@ -34,10 +40,16 @@ Hybrid 架构设计的第一要考虑的问题就是如何设计前端与 Native
2. 通讯录、系统、设备信息读取接口 2. 通讯录、系统、设备信息读取接口
3. H5 与 Native 的互相跳转。比如 H5 如何跳转到一个 Native 页面H5 如何新开 Webview 并做动画跳转到另一个 H5 页面 3. H5 与 Native 的互相跳转。比如 H5 如何跳转到一个 Native 页面H5 如何新开 Webview 并做动画跳转到另一个 H5 页面
### 账号信息设计 ### 账号信息设计
账号系统是重要且无法避免的Native 需要设计良好安全的身份验证机制,保证这块对业务开发者足够透明,打通账户体系 账号系统是重要且无法避免的Native 需要设计良好安全的身份验证机制,保证这块对业务开发者足够透明,打通账户体系
### Hybrid 开发调试 ### Hybrid 开发调试
功能设计、编码完并不是真正结束Native 与前端需要商量出一套可开发调试的模型,不然很多业务开发的工作难以继续。 功能设计、编码完并不是真正结束Native 与前端需要商量出一套可开发调试的模型,不然很多业务开发的工作难以继续。
@@ -54,6 +66,7 @@ Android 调试技巧:
## Hybrid 交互设计 ## Hybrid 交互设计
Hybrid 交互无非是 Native 调用 H5 页面JS 方法,或者 H5 页面通过 JS 调 Native 提供的接口。2者通信的桥梁是 Webview。 Hybrid 交互无非是 Native 调用 H5 页面JS 方法,或者 H5 页面通过 JS 调 Native 提供的接口。2者通信的桥梁是 Webview。
@@ -66,6 +79,9 @@ weixin:// 可以打开微信。
关于 Url scheme 如果不太清楚可以看看 [这篇文章](https://www.jianshu.com/p/253479ccc83a) 关于 Url scheme 如果不太清楚可以看看 [这篇文章](https://www.jianshu.com/p/253479ccc83a)
### JS to Native ### JS to Native
Native 在每个版本都会提供一些 Api前端会有一个对应的框架团队对其封装释放业务接口。举例 Native 在每个版本都会提供一些 Api前端会有一个对应的框架团队对其封装释放业务接口。举例
@@ -98,6 +114,8 @@ SDGHybridReady(function(arg){
前端框架定义了一个全局变量 SDGHybrid 作为 Native 与前端交互的桥梁,前端可以通过这个对象获得访问 Native 的能力 前端框架定义了一个全局变量 SDGHybrid 作为 Native 与前端交互的桥梁,前端可以通过这个对象获得访问 Native 的能力
### Api 交互 ### Api 交互
调用 Native Api 接口的方式和使用传统的 Ajax 调用服务器,或者 Native 的网络请求提供的接口相似 调用 Native Api 接口的方式和使用传统的 Ajax 调用服务器,或者 Native 的网络请求提供的接口相似
@@ -108,6 +126,8 @@ SDGHybridReady(function(arg){
![通信示例](https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/master/assets/Hybrid-Ajax.jpg) ![通信示例](https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/master/assets/Hybrid-Ajax.jpg)
### 格式约定 ### 格式约定
交互的第一步是设计数据格式。这里分为请求数据格式与响应数据格式,参考 Ajax 模型: 交互的第一步是设计数据格式。这里分为请求数据格式与响应数据格式,参考 Ajax 模型:
@@ -160,7 +180,7 @@ Native 的 webview 环境可以监控内部任何的资源请求,判断如果
简易版本代码实现。 简易版本代码实现。
``` ```javascript
//通用的 Hybrid call Native //通用的 Hybrid call Native
window.SDGbrHybrid = window.SDGbrHybrid || {}; window.SDGbrHybrid = window.SDGbrHybrid || {};
var loadURL = function (url) { var loadURL = function (url) {
@@ -228,7 +248,7 @@ Native 对于 H5 来说有个 Webview 容器,框架&&底层不太关心 H5 的
上面的网络访问 Native 代码iOS为例 上面的网络访问 Native 代码iOS为例
``` ```objective-c
typedef NS_ENUM(NSInteger){ typedef NS_ENUM(NSInteger){
Hybrid_Request_Method_Post = 0, Hybrid_Request_Method_Post = 0,
Hybrid_Request_Method_Get = 1 Hybrid_Request_Method_Get = 1
@@ -272,10 +292,15 @@ typedef NS_ENUM(NSInteger){
``` ```
## 常用交互 Api ## 常用交互 Api
良好的交互设计是第一步,在真实业务开发中有一些 Api 一定会由应用场景。 良好的交互设计是第一步,在真实业务开发中有一些 Api 一定会由应用场景。
### 跳转 ### 跳转
跳转是 Hybrid 必用的 Api 之一,对前端来说有以下情况: 跳转是 Hybrid 必用的 Api 之一,对前端来说有以下情况:
- 页面内跳转,与 Hybrid 无关 - 页面内跳转,与 Hybrid 无关
@@ -334,6 +359,9 @@ requestHybrid({
back 与 forward 一致,可能会有 animatetype 参数决定页面切换的时候的动画效果。真实使用的时候可能会全局封装方法去忽略 tagname 细节。 back 与 forward 一致,可能会有 animatetype 参数决定页面切换的时候的动画效果。真实使用的时候可能会全局封装方法去忽略 tagname 细节。
## Header 组件的设计 ## Header 组件的设计
Native 每次改动都比较“慢”,所以类似 Header 就很需要。 Native 每次改动都比较“慢”,所以类似 Header 就很需要。
@@ -355,7 +383,7 @@ PS Native 打开 H5如果 300ms 没有响应则需要 loading 组件,避
所以站在前端业务方来说Header 的使用方式为(其中 tagname 是不允许重复的): 所以站在前端业务方来说Header 的使用方式为(其中 tagname 是不允许重复的):
``` ```javascript
//Native以及前端框架会对特殊tagname的标识做默认回调如果未注册callback或者点击回调callback无返回则执行默认方法 //Native以及前端框架会对特殊tagname的标识做默认回调如果未注册callback或者点击回调callback无返回则执行默认方法
// back前端默认执行History.back如果不可后退则回到指定URLNative如果检测到不可后退则返回Naive大首页 // back前端默认执行History.back如果不可后退则回到指定URLNative如果检测到不可后退则返回Naive大首页
// home前端默认返回指定URLNative默认返回大首页 // home前端默认返回指定URLNative默认返回大首页
@@ -403,7 +431,7 @@ PS Native 打开 H5如果 300ms 没有响应则需要 loading 组件,避
因为 Header 左边一般来说只有一个按钮,所以其对象可以使用这种形式: 因为 Header 左边一般来说只有一个按钮,所以其对象可以使用这种形式:
``` ```javascript
this.header.set({ this.header.set({
back: function () { }, back: function () { },
title: '' title: ''
@@ -420,7 +448,7 @@ this.header.set({
为完成 Native 端的实现,这里会新增两个接口,向 Native 注册事件,以及注销事件: 为完成 Native 端的实现,这里会新增两个接口,向 Native 注册事件,以及注销事件:
``` ```javascript
var registerHybridCallback = function (ns, name, callback) { var registerHybridCallback = function (ns, name, callback) {
if(!window.Hybrid[ns]) window.Hybrid[ns] = {}; if(!window.Hybrid[ns]) window.Hybrid[ns] = {};
window.Hybrid[ns][name] = callback; window.Hybrid[ns][name] = callback;
@@ -434,7 +462,7 @@ var unRegisterHybridCallback = function (ns) {
Native Header 组件实现: Native Header 组件实现:
``` ```javascript
define([], function () { define([], function () {
'use strict'; 'use strict';
@@ -558,9 +586,11 @@ define([], function () {
}); });
}); });
``` ```
## 请求类 ## 请求类
虽然 get 类请求可以用 jsonp 方式绕过跨域问题,但是 post 请求是一个拦路虎。为了安全性问题服务器会设置 cors 仅仅针对几个域名Hybrid 内嵌静态资源可能是通过本地 file 的方式读取,所以 cors 就行不通了。另外一个问题是防止爬虫获取数据,由于 Native 针对网络做了安全性设置(鉴权、防抓包等),所以 H5 的网络请求由 Native 完成。可能有些人说 H5 的网络请求让 Native 走就安全了吗?我可以继续爬取你的 Dom 节点啊。这个是针对反爬虫的手段一。想知道更多的反爬虫策略可以看看我这篇文章 [Web反爬虫方案](https://github.com/FantasticLBP/Anti-WebSpider) 虽然 get 类请求可以用 jsonp 方式绕过跨域问题,但是 post 请求是一个拦路虎。为了安全性问题服务器会设置 cors 仅仅针对几个域名Hybrid 内嵌静态资源可能是通过本地 file 的方式读取,所以 cors 就行不通了。另外一个问题是防止爬虫获取数据,由于 Native 针对网络做了安全性设置(鉴权、防抓包等),所以 H5 的网络请求由 Native 完成。可能有些人说 H5 的网络请求让 Native 走就安全了吗?我可以继续爬取你的 Dom 节点啊。这个是针对反爬虫的手段一。想知道更多的反爬虫策略可以看看我这篇文章 [Web反爬虫方案](https://github.com/FantasticLBP/Anti-WebSpider)
@@ -569,7 +599,7 @@ define([], function () {
这个使用场景和 Header 组件一致,前端框架层必须做到对业务透明化,业务事实上不必关心这个网络请求到底是由 Native 还是浏览器发出。 这个使用场景和 Header 组件一致,前端框架层必须做到对业务透明化,业务事实上不必关心这个网络请求到底是由 Native 还是浏览器发出。
``` ```javascript
HybridGet = function (url, param, callback) { HybridGet = function (url, param, callback) {
}; };
@@ -580,7 +610,7 @@ HybridPost = function (url, param, callback) {
真实的业务场景会将之封装到数据请求模块在底层做适配在H5站点下使用ajax请求在Native内嵌时使用代理发出与Native的约定为 真实的业务场景会将之封装到数据请求模块在底层做适配在H5站点下使用ajax请求在Native内嵌时使用代理发出与Native的约定为
``` ```javascript
requestHybrid({ requestHybrid({
tagname: 'NativeRequest', tagname: 'NativeRequest',
param: { param: {
@@ -595,11 +625,14 @@ requestHybrid({
}); });
``` ```
## 常用 NativeUI 组件 ## 常用 NativeUI 组件
一般情况 Native 通常会提供常用的 UI比如 加载层loading、消息框toast 一般情况 Native 通常会提供常用的 UI比如 加载层loading、消息框toast
``` ```javascript
var HybridUI = {}; var HybridUI = {};
HybridUI.showLoading(); HybridUI.showLoading();
//=> //=>
@@ -629,6 +662,7 @@ Native UI与前端UI不容易打通所以在真实业务开发过程中
## 账号系统的设计 ## 账号系统的设计
Webview 中跑的网页,账号登录与否由是否携带密钥 cookie 决定(不能保证密钥的有效性)。因为 Native 不关注业务实现,所以每次载入都有可能是登录成功跳转回来的结果,所以每次载入都需要关注密钥 cookie 变化,以做到登录态数据的一致性。 Webview 中跑的网页,账号登录与否由是否携带密钥 cookie 决定(不能保证密钥的有效性)。因为 Native 不关注业务实现,所以每次载入都有可能是登录成功跳转回来的结果,所以每次载入都需要关注密钥 cookie 变化,以做到登录态数据的一致性。
@@ -665,15 +699,13 @@ HybridUI.logout = function () {
``` ```
在设计 Hybrid 层的时候,接口要做到对于处于 Hybrid 环境中的代码乐意通过接口获取 Native 端存储的用户账号信息;对于处于传统的网页环境,可以通过接口获取线上的账号信息,然后将非敏感的信息存储到 LocalStorage 中,然后每次页面加载从 LocalStorage 读取数据到内存中(比如 Vue.js 框架中的 VuexReact.js 中的 Redux 在设计 Hybrid 层的时候,接口要做到对于处于 Hybrid 环境中的代码乐意通过接口获取 Native 端存储的用户账号信息;对于处于传统的网页环境,可以通过接口获取线上的账号信息,然后将非敏感的信息存储到 LocalStorage 中,然后每次页面加载从 LocalStorage 读取数据到内存中(比如 Vue.js 框架中的 VuexReact.js 中的 Redux
## Hybrid 资源管理 ## Hybrid 资源管理
Hybrid 的资源需要 `增量更新` 需要拆分方便,所以一个 Hybrid 资源结构类似于下面的样子 Hybrid 的资源需要 `增量更新` 需要拆分方便,所以一个 Hybrid 资源结构类似于下面的样子
![Hybrid资源结构](https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/master/assets/2019-07-08-Hybrid-ResourceStructure.png) ![Hybrid资源结构](https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/master/assets/2019-07-08-Hybrid-ResourceStructure.png)
@@ -705,29 +737,24 @@ WebApp
## 增量更新 ## 增量更新
每次业务开发完毕后都需要在打包分发平台进行部署上线,之后会生成一个版本号。 每次业务开发完毕后都需要在打包分发平台进行部署上线,之后会生成一个版本号。
| Channel | Version | md5 | | Channel | Version | md5 |
| ------- | ------- | ----------- | | ------- | ------- | ----------- |
| Mall | 1.0.1 | 12233000ww | | Mall | 1.0.1 | 12233000ww |
| Cart | 1.1.2 | 28211122wt2 | | Cart | 1.1.2 | 28211122wt2 |
当 Native App 启动的时候会从服务端请求一个接口,接口的返回一个 json 串,内容是 App 所包含的各个 H5 业务线的版本号和 md5 信息。 当 Native App 启动的时候会从服务端请求一个接口,接口的返回一个 json 串,内容是 App 所包含的各个 H5 业务线的版本号和 md5 信息。
拿到 json 后和 App 本地保存的版本信息作比较,发现变动了则去请求相应的接口,接口返回 md5 对应的文件。Native 拿到后完成解压替换。 拿到 json 后和 App 本地保存的版本信息作比较,发现变动了则去请求相应的接口,接口返回 md5 对应的文件。Native 拿到后完成解压替换。
全部替换完毕后将这次接口请求到的资源版本号信息保存替换到 Native 本地。 全部替换完毕后将这次接口请求到的资源版本号信息保存替换到 Native 本地。
因为是每个资源有版本号,所以如果线上的某个版本存在问题,那么可以根据相应的稳定的版本号回滚到稳定的版本。 因为是每个资源有版本号,所以如果线上的某个版本存在问题,那么可以根据相应的稳定的版本号回滚到稳定的版本。

View File

@@ -606,7 +606,9 @@ $ node app.js
目前 App 的网络通信基本都是用 HTTPS 的服务,但是随便一个抓包工具都是可以看到 HTTPS 接口的详细数据,为了做到防止抓包和无法模拟接口的情况,我们采取以下措施: 目前 App 的网络通信基本都是用 HTTPS 的服务,但是随便一个抓包工具都是可以看到 HTTPS 接口的详细数据,为了做到防止抓包和无法模拟接口的情况,我们采取以下措施:
1. 中间人盗用数据,我们可以采取 HTTPS 证书的双向认证,这样子实现的效果就是中间人在开启抓包软件分析 App 的网络请求的时候,网络会自动断掉,无法查看分析请求的情况 1. 中间人盗用数据,我们可以采取 HTTPS 证书的双向认证,这样子实现的效果就是中间人在开启抓包软件分析 App 的网络请求的时候,网络会自动断掉,无法查看分析请求的情况
2. 对于防止用户模仿我们的请求再次发起请求,我们可以采用 「防重放策略」,用户再也无法模仿我们的请求,再次去获取数据了。 2. 对于防止用户模仿我们的请求再次发起请求,我们可以采用 「防重放策略」,用户再也无法模仿我们的请求,再次去获取数据了。
3. 对于 App 内的 H5 资源反爬虫方案可以采用上面的解决方案H5 内部的网络请求可以通过 Hybrid 层让 Native 的能力去完成网络请求,完成之后将数据回调给 JS。这么做的目的是往往我们的 Native 层有完善的账号体系和网络层以及良好的安全策略、鉴权体系等等。 3. 对于 App 内的 H5 资源反爬虫方案可以采用上面的解决方案H5 内部的网络请求可以通过 Hybrid 层让 Native 的能力去完成网络请求,完成之后将数据回调给 JS。这么做的目的是往往我们的 Native 层有完善的账号体系和网络层以及良好的安全策略、鉴权体系等等。
<details> <details>
<summary>JS端发起网络请求代码点击展开</summary> <summary>JS端发起网络请求代码点击展开</summary>
@@ -656,7 +658,17 @@ $ node app.js
``` ```
</details> </details>
4. 有些人觉得利用 RSA 加密虽然可以保证数据的安全,但是因为每次都是大量字符串的运算,觉得数据量大的情况下用 RSA 加解密会非常耗时。对,肯定耗时,所以较好的做法就是将通信的 Alice 和 Bob 两方利用 **RSA** 的方式交换密钥。然后两方在通信的时候数据内容采用**对称加密**的方式进行。但是私钥在本地如何存放呢?想到的办法就是将关键密钥的字符串提高到较高的安全级别,比如这个文件用加密保存。接下来推荐一个[工具](https://github.com/RNCryptor/RNCryptor),可以将代码文件进行加密保存和解密访问 4. 针对抓包工具可以截获 HTTPS 数据的情况,我们可以对请求参数和返回内容再做一次 **RSA** 加密处理
- 客户端和服务器各自生成公钥、私钥
- 互相交换公钥
- 通信流程:客户端利用服务端的公钥加密请求参数 -> 服务端收到请求后利用服务端的私钥解密,验证合法性 -> 做可能的逻辑处理DB、缓存、ES,组装数据 -> 处理数据到合适的格式 -> 利用客户端公钥加密数据 -> 客户端收到数据后利用客户端私钥解密。(服务器主动发起的请求也是一样的逻辑)
有些人觉得利用 RSA 加密虽然可以保证数据的安全,但是因为每次都是大量字符串的运算,觉得数据量大的情况下用 RSA 加解密会非常耗时。
对,肯定耗时,所以较好的做法就是将通信双方使用的密钥(对称加密)利用 **RSA** 的方式交换,然后两方在通信的时候,数据内容采用**对称加密**的方式进行。
但是私钥在本地如何存放呢?想到的办法就是将关键密钥的字符串提高到较高的安全级别,比如这个文件用加密保存。接下来推荐一个[工具](https://github.com/RNCryptor/RNCryptor),可以将代码文件进行加密保存和解密访问。
@@ -674,7 +686,7 @@ $ node app.js
以上是第一阶段的安全性总结,后期应该会更新App逆向、防重放、Canvas 反爬虫技术方案做深入探讨等)。 以上是第一阶段的安全性总结,后期会从更多、更深入的角度剖析大前端安全性的策略和方案
补充: 补充:

View File

@@ -15,7 +15,8 @@ API 接口存在很多常见的安全性问题,常见的有下面几种情况
所以针对上述的问题也有一些解决方案: 所以针对上述的问题也有一些解决方案:
1. HTTPS 证书的双向认证解决抓包工具问题 1. HTTPS 证书的双向认证解决抓包工具问题
2. 假如通过网络层高手截获了 HTTPS 加证书认证后的数据,所以需要对请求参数做签名 2. 假如通过网络层高手截获了 HTTPS 加证书认证后的数据,所以需要对请求参数做签名
2. 「防重放策略」解决请求的多次发起问题 3. 「防重放策略」解决请求的多次发起问题
4. 请求参数和返回内容做额外 RSA 加密处理,即使截获,也无法查看到明文。
关于 HTTPS 证书双向认证和 Web 端反爬虫技术方案均在[大前端时代的安全性](https://github.com/FantasticLBP/knowledge-kit/blob/master/Chapter1%20-%20iOS/1.56.md)一文中有具体讲解。接下来引出本文主角:防重放 关于 HTTPS 证书双向认证和 Web 端反爬虫技术方案均在[大前端时代的安全性](https://github.com/FantasticLBP/knowledge-kit/blob/master/Chapter1%20-%20iOS/1.56.md)一文中有具体讲解。接下来引出本文主角:防重放
@@ -96,7 +97,11 @@ API 接口存在很多常见的安全性问题,常见的有下面几种情况
## 四、 计算机网络时间同步技术原理 ## 四、 计算机网络时间同步技术原理
客户端和服务端的时间同步在很多场景下非常重要,比如秒杀系统(页面打开,各个类目的商品展示倒计时秒杀功能。如果直接请求接口页面数据,然后拿到服务器时间进行倒计时,则会因为网络传输的耗时,导致时间不精确)、接口 timestamp 等 客户端和服务端的时间同步在很多场景下非常重要,举几个例子,这些场景都是经常发生的
- 一个商品秒杀系统。用户打开页面,浏览各个类目的商品,商品列表界面右侧和详情页都有倒计时秒杀功能。用户在详情页加购、下单、结算。发现弹出提示“商品库存不足,请购买同类其他品牌商品”
- 一个答题系统,题目是该公司核心竞争力。所以有心的程序员为接口设计了「防重放」功能。但是前端小哥不给力,接口带过去的 timestamp 与服务器不在一个时区,差好几秒。别有用心的竞品公司的爬虫工程师发现了该漏洞,爬取了题目数据。
所以该现象在计算机领域有非常普遍,有解决方案。
1. 如果精度要求不高的情况下:先请求服务器上的时间 ServerTime然后记录下来同时记录当前的时间 LocalTime1需要获取当前的时间时用最新的当前时间 (LocalTime2 - LocalTime1 + ServerTime) 1. 如果精度要求不高的情况下:先请求服务器上的时间 ServerTime然后记录下来同时记录当前的时间 LocalTime1需要获取当前的时间时用最新的当前时间 (LocalTime2 - LocalTime1 + ServerTime)
@@ -109,4 +114,4 @@ API 接口存在很多常见的安全性问题,常见的有下面几种情况
2. 如果需要精度更高,比如 100纳秒的情况则需要使用 NTPNetwork Time Protocol网络时间协议、PTP Precision Time Protocol精确时间同步协议了。 2. 如果需要精度更高,比如 100纳秒的情况则需要使用 NTPNetwork Time Protocol网络时间协议、PTP Precision Time Protocol精确时间同步协议了。
NTP、PTP 不在本文的范畴,不懂得可以查看这篇[文章](https://segmentfault.com/a/1190000005337116) NTP、PTP 不在本文的范畴,感兴趣的可以查看这篇[文章](https://segmentfault.com/a/1190000005337116)

View File

@@ -7,12 +7,14 @@
## 实现 ## 实现
可以马上想到的是利用 shell 结合 git hook 实现在 git commit 阶段检查输入是否符合规范。符合就通过,不符合就不通过,抛出警告信息,并给出提示信息。 可以马上想到的是利用 shell 结合 git hook 实现在 git commit 阶段检查输入是否符合规范。符合就通过,不符合就终止,并给出提示信息。
### 规范是什么 ### 规范是什么
常见的分类有下面几种情况 常见的分类有下面几种:
- build修改项目的的构建系统xcodebuild、webpack、glup等的提交 - build修改项目的的构建系统xcodebuild、webpack、glup等的提交
- ci修改项目的持续集成流程Kenkins、Travis等的提交 - ci修改项目的持续集成流程Kenkins、Travis等的提交
@@ -28,6 +30,7 @@
### 轮子 ### 轮子
在 github 上有 [commitlint](https://github.com/conventional-changelog/commitlint) 这个项目,它可以很方便的在工程中做配置,并允许你自定义上面说的「规范」、「分类」。 在 github 上有 [commitlint](https://github.com/conventional-changelog/commitlint) 这个项目,它可以很方便的在工程中做配置,并允许你自定义上面说的「规范」、「分类」。
@@ -92,23 +95,18 @@
``` ```
上面的流程配置完成,当你在提交 commit 信息的时候如果输入不符合 `<type>: <subject>` 规则,会给出提示信息。 上面的流程配置完成,当你在提交 commit 信息的输入的内容,如果不符合 `<type>: <subject>` 规则,会终止并给出提示信息。
type 就是上面的种类subject 就是需要提交的文字概括。比如feature增加摇一摇推荐酒店功能。 type 就是上面的种类subject 就是需要提交的文字概括。比如feature增加摇一摇推荐酒店功能。
小说明:如果某次提交想禁用 husky可以添加参数 **--no-verify**。`git commit --no-verify -m "xxx"`
小说明:
- 如果某次提交想禁用 husky可以添加参数 `--no-verify`
```shell
git commit --no-verify -m "xxx"
```
### 大体流程 ### 流程说明
安装包 husky 的时候,会在目录 `.git/hooks/` 下生成一堆 shell 脚本,负责 hook git 相关时机 安装包 husky 的时候,会在目录 `.git/hooks/` 下生成一堆 shell 脚本,负责 git 的 hook
`"commit-msg": "commitlint -E HUSKY_GIT_PARAMS"` 这个配置告诉 git hooks当执行 `git commit -m` 的时候触发 commit-msg 钩子,并通知 husky从而执行 `commitlint -E HUSKY_GIT_PARAMS`,实际上执行的是 `./node_modules/husky/bin/run.js`,读取 commitlint.config.js 里的配置,然后对我们 commit -m 里的字符串校验,如不通过则输出错误信息并终止。 `"commit-msg": "commitlint -E HUSKY_GIT_PARAMS"` 这个配置告诉 git hooks当执行 `git commit -m` 的时候触发 commit-msg 钩子,并通知 husky从而执行 `commitlint -E HUSKY_GIT_PARAMS`,实际上执行的是 `./node_modules/husky/bin/run.js`,读取 commitlint.config.js 里的配置,然后对我们 commit -m 里的字符串校验,如不通过则输出错误信息并终止。