前端Date.now问题分析以及解决方案

new Date() 与 Date.now()

相信很多前端同学对这个方法很熟悉。

1
2
new Date() // 返回一日期对象 Fri Nov 24 2017 15:53:18 GMT+0800 (CST)
Date.now() // 返回1970 年 1 月 1日午夜与当前日期和时间之间的毫秒数。 1511510039726

在很多场景中,前端会习惯性的获取当前时间,然后去进行逻辑处理与后端交互。
我们在做很多活动抽奖已经机票查询日历的时候,只能允许用户点击当前时间之后的。
今天我们那机票的场景来做介绍,我们在进入机票的搜索页,我们需要给用户默认一个时间,这个时间会默认给用户显示。

服务端 & 客户端

我们很多时候会直接使用new Date(),进行初始化时间,如果没有,我们会默认加1天。
但是这里有一个问题,如果用户的本地时间不准确,慢当前时间,就会跳过一个逻辑,选择的时间只能在今天之后。
所以,我们这里会采用服务端时间来进行计算。

实现方法3步
1.服务端把当前时间嵌入到前端
2.前端获取服务端时间使用,通过方法调用。(这里需要方法处理)
3.前端调用统一的方法来进行调用
待续。。

lodash 解析

“Array” 方法

_.chunk(array, [size=1]);
将数组(array)拆分成多个 size 长度的区块,并将这些区块组成一个新数组。 如果array 无法被分割成全部等长的区块,那么最后剩余的元素将组成一个区块。
参数
array (Array): 需要处理的数组
[size=1] (number): 每个数组区块的长度
返回
(Array): 返回一个包含拆分区块的新数组(愚人码头注:相当于一个二维数组)。

1
2
3
4
5
6
7
例子

_.chunk(['a', 'b', 'c', 'd'], 2);
// => [['a', 'b'], ['c', 'd']]

_.chunk(['a', 'b', 'c', 'd'], 3);
// => [['a', 'b', 'c'], ['d']]

源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
function chunk(array, size, guard) {
if ((guard ? isIterateeCall(array, size, guard) : size === undefined)) {
size = 1;
} else {
size = nativeMax(toInteger(size), 0);
}
var length = array == null ? 0 : array.length;
if (!length || size < 1) {
return [];
}
var index = 0,
resIndex = 0,
result = Array(nativeCeil(length / size));

while (index < length) {
result[resIndex++] = baseSlice(array, index, (index += size));
}
return result;
}

express参数过滤

express 介绍

Express 是一个基于 Node.js 平台的极简、灵活的 web 应用开发框架,它提供一系列强大的特性,帮助你创建各种 Web 和移动设备应用。

简单说下参数安全

今天说下,参数过滤,我们结果对外暴露的所有接口参数,我们需要在request接收的时候,进行参数校验,说白一点,不管是入参还是出参,我们都得做好统一处理。

今天我来在express里面来给大家讲下如何实现参数校验。
1.首先我们定义一个路由

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
index.js

module.exports = app => {
app.use('/validateData', validate);

app.use('/', page);
};

route.js

var express = require('express');
var router = express.Router();
var validate = require('../controller/common/validate');
var apiWrapperReq = require('../middleware/apiWrapperReq');

router.get('/', apiWrapperReq.wrapperReq, validate.fetch);

module.exports = router;

2.我们需要给路由一个中间件。来控制参数,这里地方的apiwrapperReq里面需要做好处理。

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
// 校验类型
validate(rules, params) {
let result = { ret: true, msg: [], data: {} };
let msg = [];
if (!params) {
return result;
}

_.each(rules, (type, key) => {
let key_rule = typeof type === 'object' ? type : { type };
let val = params[key];

// 是否必须
let required = key_rule.required && key_rule.required === true;
if (required && undefined === val) {
msg.push(`param ${key} is required!`);
}

// 转换类型,这里可以过滤非法字符,后面加入正则过滤
if (undefined !== val && val) {
try {
// 检查参数数据正则表达式的健壮性
if (!safe(val)) {
msg.push(`param ${key} is no no no!`);
}

// 转换一下。转换失败,不通过。
params[key] = this.convertType(val, key_rule);
} catch (ex) {
msg.push(`param ${key} is error!`);
}
}
});

return {
ret: msg.length === 0,
msg: msg,
data: params
};
}

3.上面的接受了2个参数,一个是rules,一个params。我们需要获取一个rules。对应每一个接口都得有一个rules。下面我们整理下规则的参数

我们需要对参数是否必须填写和参数的类型进行转换。这样保证我们的参数合法性。

1
2
3
4
5
6
7
8
9
10
module.exports = {
queryA: {
required: true,
type: 'string'
},
queryB: {
required: true,
type: 'int'
}
};

按照上述步骤去走我们的流程,判断下有校验规则的才走逻辑。不然跳过。我们知道做这个目的是,过滤一些正则表达式的攻击,防止参数中含有正则表达式的一些进行攻击数据库。简单的做一层。如果你觉得你的正则表达式不是很优雅,可以采用第三方库(safe-regex).来帮你你完成。

为什么每天学习一点算法

为什么算法?

大家都知道,作为前端工程师,那么传统类型的前端,大家都认为的是只需要简单的写一些页面,和页面交互就可以完成的工作,但是,近几年对前端工程师的热度越来越高,对前端的要求也越来越高,很多时候前端需要完成更加复杂的交互和业务功能。
前端工程师也在成长,这些年推出了很多模块化,组件化,当然前端的开发工程也不是之前的html和css以及js那么简单的,注入了工程化东西。gulp,webpack都是来打包和编译我们的js和前端工程的。
css也有了预处理语言,scss和less大家应该不会陌生。
。。。
其他前端这几年的框架也很多这里不去论述框架,react/vue。

算法重要吗?

我们在开发前端的时候,开始使用后端语言,node.js成为了前端工程师的首选,当然很多公司也在用java,php,甚至很多大型互联网公司还在用C#,所以,这个时候的前端算法就体现的很重要。
大部分前端工程师,因为这几年的热门,通过培训机构出来,甚至其他专业转过来,对计算机软件的思维理解不够深入,当然前端上手很容易,成为了他们的首选。

每天学习一点算法

笔者大学软件工程专业出身,在学校的时候已经开始和老师同学开始项目开发,java、php、c#、node.js都有实际的项目开发经验,当然前端的开发浪潮本人也身在其中。
当然前端只是完成现有的功能也是可以的,如果你要想做一个好的前端工程师,你得好好学习算法,笔者也是专业出身,现在对算法也是很多不懂,所以,今天开始,会同大家一起每天学习一点算法,同事记录笔记。

每天学习一点算法

目录

es6读书笔记

es6读书笔记

本文主要学习和复习es6,学习同时会对lodash.js进行分析.感谢阮一峰老师

Promise 对象

webpack简单介绍

webpack简介

什么是webpack

WebPack可以看做是模块打包机:它做的事情是,分析你的项目结构,找到JavaScript模块以及其它的一些浏览器不能直接运行的拓展语言(Scss,TypeScript等),并将其转换和打包为合适的格式供浏览器使用。

为什么webpack?

现今的很多网页其实可以看做是功能丰富的应用,它们拥有着复杂的JavaScript代码和一大堆依赖包。为了简化开发的复杂度,前端社区涌现出了很多好的实践方法

模块化,让我们可以把复杂的程序细化为小的文件;
类似于TypeScript这种在JavaScript基础上拓展的开发语言:使我们能够实现目前版本的JavaScript不能直接使用的特性,并且之后还能转换为JavaScript文件使浏览器可以识别;
Scss,less等CSS预处理器

这些改进确实大大的提高了我们的开发效率,但是利用它们开发的文件往往需要进行额外的处理才能让浏览器识别,而手动处理又是非常繁琐的,这就为WebPack类的工具的出现提供了需求。

webpack配置

webpack插件

webpack插件编写

webpack2& & webpack3?

yield

node简单防刷

简单的安全防范

web时代的今天,我们经常会暴露一些接口给外网,但是很多作为前端工程师,也是需要在互联网的今天做一点攻防。不能直接让人直接访问你的接口,所以,本篇文章主要简单的介绍下。如何的简单的实现防刷。

文章主要采用node.js作为介绍。

首先,我们理解下,一个接口没有任何防刷。你只需要打开浏览器,直接找到对应的接口,直接刷新就可以直接搞定接口。这样我们的风险还是很高的。让刷的难度稍微高一点。

最简单的做法就是,Token验证和访问限制。

1.我们需要server端生成一段随机数。

1
2
3
4
injectAccessToken(req, res, next) {
req._access_token = Math.random().toString(26).slice(2);
next();
}

2.把Token注入到页面中

1
2
3
4
5
6
7
8
9
webInject:function(html,token,callback){
var htmlEndIndex = html.indexOf('</html>');
var tokenScript = '<script>window.' + this.config.webTokenVarName + '=' + token + '</script>';
var prevHtml = html.substring(0, htmlEndIndex);
var nextHtml = html.substr(htmlEndIndex);
prevHtml += tokenScript;
prevHtml += nextHtml;
callback(null, prevHtml);
}

3.页面请求把Token带回来

页面请求带着自定义的Token回传,注意,这个地方可以自己实现一些算法和混淆的东西。我这里提供一个东西。就是通过字符串拆分,把生成的Token放在html中,获取的时候也是随机的。达到每次获取都不一样。
记住标签随机,id值随机生成,在server端输出给html。

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
<samp id="_CWXF0" style="display:none;">f</samp>
<i id="_CWXF1" style="display:none;">k</i>
<sub id="_CWXF2" style="display:none;">2</sub>
<tt id="_CWXF3" style="display:none;">d</tt>
<bdo id="_CWXF4" style="display:none;">f</bdo>
<b id="_CWXF5" style="display:none;">d</b>
<cite id="_CWXF6" style="display:none;">7</cite>
<tt id="_CWXF7" style="display:none;">b</tt>
<code id="_CWXF8" style="display:none;">e</code>
<dfn id="_CWXF9" style="display:none;">g</dfn>
<time id="_CWXF10" style="display:none;">3</time>
<code id="_CWXF11" style="display:none;">8</code>
<sub id="_CWXF12" style="display:none;">1</sub>
<code id="_CWXF13" style="display:none;">a</code>
<em id="_CWXF14" style="display:none;">o</em>
<bdo id="_CWXF15" style="display:none;">b</bdo>
<i id="_CWXF16" style="display:none;">d</i>
<i id="_CWXF17" style="display:none;">e</i>
<sup id="_CWXF18" style="display:none;">j</sup>
<small id="_CWXF19" style="display:none;">9</small>
<code id="_CWXF20" style="display:none;">m</code>
<em id="_CWXF21" style="display:none;">4</em>
<small id="_CWXF22" style="display:none;">9</small>
<cite id="_CWXF23" style="display:none;">c</cite>
<abbr id="_CWXF24" style="display:none;">g</abbr>
<tt id="_CWXF25" style="display:none;">5</tt>
<code id="_CWXF26" style="display:none;">h</code>
<sup id="_CWXF27" style="display:none;">6</sup>
<sub id="_CWXF28" style="display:none;">5</sub>
<span id="_CWXF29" style="display:none;">f</span>
<sup id="_CWXF30" style="display:none;">0</sup>
<i id="_CWXF31" style="display:none;">3</i>
<label id="_CWXF32" style="display:none;">7</label>
<span id="_CWXF33" style="display:none;">e</span>
<code id="_CWXF34" style="display:none;">9</code>
<label id="_CWXF35" style="display:none;">6</label>
<bdo id="_CWXF36" style="display:none;">3</bdo>
<code id="_CWXF37" style="display:none;">b</code>
<cite id="_CWXF38" style="display:none;">3</cite>
<acronym id="_CWXF39" style="display:none;">3</acronym>
<sub id="_CWXF40" style="display:none;">m</sub>
<dfn id="_CWXF41" style="display:none;">8</dfn>
<map id="_CWXF42" style="display:none;">o</map>
<strong id="_CWXF43" style="display:none;">9</strong>
<sup id="_CWXF44" style="display:none;">j</sup>
<em id="_CWXF45" style="display:none;">d</em>
<script>
(function(w){
var r = "";
function g(id){
return document.getElementById(id).innerHTML;
}
r += g("_CWXF0");r += g("_CWXF1");r += g("_CWXF2");r += g("_CWXF3");
r += g("_CWXF4");r += g("_CWXF5");r += g("_CWXF6");r += g("_CWXF7");
r += g("_CWXF8");r += g("_CWXF9");r += g("_CWXF10");r += g("_CWXF11");
r += g("_CWXF12");r += g("_CWXF13");r += g("_CWXF14");r += g("_CWXF15");
r += g("_CWXF16");r += g("_CWXF17");r += g("_CWXF18");r += g("_CWXF19");
r += g("_CWXF20");r += g("_CWXF21");r += g("_CWXF22");r += g("_CWXF23");
r += g("_CWXF24");r += g("_CWXF25");r += g("_CWXF26");r += g("_CWXF27");
r += g("_CWXF28");r += g("_CWXF29");r += g("_CWXF30");r += g("_CWXF31");
r += g("_CWXF32");r += g("_CWXF33");r += g("_CWXF34");r += g("_CWXF35");
r += g("_CWXF36");r += g("_CWXF37");r += g("_CWXF38");r += g("_CWXF39");
r += g("_CWXF40");r += g("_CWXF41");r += g("_CWXF42");r += g("_CWXF43");
r += g("_CWXF44");r += g("_CWXF45");
w.tokenName=r;
})(window)
</script>

4.校验token是否合法

在路由的地方加入拦截器,达到获取Token的目的,这里为了统一处理前端,建议放在header中,传递,你可以在前端统一封装的ajax处统一处理,以达到不影响业务代码的目的。

1
2
3
4
5
6
7
8
9
10
11
verifyToken(req, res, next) {
if (req.headers['token_fe']) {
next();
} else {
res.jsonp({
code: -1,
ret: false,
msg: 'access not vaildate'
});
}
}

这样就实现了最简单的Token防刷,当然重要的是,你可以把token放在内存中,内存中加入过期时间,和有效的规则,比如,一分钟这个Token请求多少次。就不能再次请求等。可以可以注入IP,以IP的模式来校验不能多次请求。

读书笔记

读书笔记

前端实用的技术整理笔记

目录