image frame

脑洞大开の乱乱想

放下碎碎念,重新出发

js模块化

在es6之前没有模块化。

原始写法

原始写法。使用时候直接调用即可,但是这样会污染全局变量,而且模块成员之间看不出直接关系,不好

1
2
function m1(){}
function m2(){}

对象写法。这样会暴露模块的所有成员,而且内部状态会被外部改写,比如 module1.__cont=5

1
2
3
4
5
6
var module1 = new Object({
_cont:0,
m1: function(){}
m2: function(){}
})
module1.m1();

立即执行函数写法,不暴露私有成员的目的

1
2
3
4
5
6
7
8
9
10
var module1 = (function(){
var _cont = 0;
var m1 = function(){}
var m2 = function(){}
return {
m1: m1,
m2: m2,
}
})()
module1.m1()

放大模式 如果一个模块很大,必须分成几个部分,或者一个模块需要继承另一个模块,这时就有必要采用 放大模式

1
2
3
4
5
var module1 = (function (mod){
mod.m3 = function(){}
return mod;
})(modle1)
// 给module1 添加了新方法 m3() 然后返回新的 module1 模块

输入全局变量 独立性是模块的重要特点,模块内部最好不和其他部分直接接触

1
2
3
var module1 = (function (%,yahoo){
...
})(jQuery, yahoo)

cjs amd es

历史的发展,commonjs 在node中依旧常用。通过 webpack 写es模块化即可。

node事件循环

  • node 的 event-loop 分6个阶段,反复运行。
  • 进入某一个阶段,会从对应的回调里取出函数去执行。
  • 当队列空,或执行的回调函数数量达到系统设定的阈值,就进入下一阶段

阶段:

  • timers 定时器
  • pending callbacks 读写回调函数
  • idle, prepare 内部
  • poll – connections 轮询
    • incoming
    • date, etc.
  • check
  • close callbacks

这里去官网看文档。
timers
执行 setTimeout setInterval 由poll阶段控制的。

I/O

I/O 阶段会处理一些上一轮循环中的少数未执行的 I/O 回调

idel, prepare
内部实现,先忽略

poll
重要,会做两件事情:

  1. 回到 timer 阶段执行回调
  2. 执行 I/O 回调

这部分来自狼书

  • 事件循环机制
    • eventloop 是 libuv的核心
    • 为了更好理解事件循环
      • 队列管理
        • process.nextTick() 入列
        • process._tickCallback 出列
      • 合适时候加入操作
        • timers
        • setImmediate()
        • io
    • 微任务microtask 和 宏任务 macrotask
      • 当前调用栈执行完毕,先处理 微任务,然后在宏任务取出一个事件并执行
        • 我们看了一个demo,需要小心推断
          • 先处理简单的,异步的部分 promise 为微任务 set系列为任务,进入任务队列
          • 经过事件循环,先执行微观,遇到宏观按顺序执行
    • process.nextTick(callback)是用于事件循环的下一次循环调用函数的。和 set p173

node里的MySQL

这里记录node连sql数据库的代码块,方便以后复用。

执行原生mysql,只考虑 mysql2 就可以。如果是通过orm的话,使用 sequelize 也没有什么争议。


先说 mysql2 它的promise async支持的比较好,目标是取代 mysql

快速入门

安装

1
yarn add mysql2

快速链接

引入包,引入环境变量,引入sql语句

callback 写法

async 写法

创建连接池得到实例,实例去query代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
const mysql = require("mysql2/promise");
const mysqlConf = {
host: "localhost",
user: "root",
password: "12345678",
database: "wp-back"
};

// 这个sql语句忽略,稍微有点复杂
const SQL = `select ID,post_title from wp_posts, wp_term_relationships,wp_terms
where (
wp_posts.post_status='publish' and
ID = wp_term_relationships.object_id and
wp_term_relationships.term_taxonomy_id = wp_terms.term_id and
wp_terms.name='企业简介'
) `
;

(async () => {
const pool = mysql.createPool(mysqlConf);
const [row, fields] = await pool.query(SQL);
console.log(row);
pool.end() // 记得关闭
})();

实际中,会把 pool 独立出去,引入。

其他配置参数

mysql2 的目标是取代 mysql ,所以都没有文档,直接去 node-mysql 上看 options

连接参数

  • host port user password database 这几项就不说了
  • localAddress 来源ip地址,用于tcp连接
  • charset 默认 UTF8_GENERAL_CI 可以指定 utf8mb4
  • timezone 时区。默认值 local+08:00
  • connectTimeout 初始化连接超时毫秒 默认10000
  • typeCast 把列和值编程js对象。默认true
  • dateString 强制把 timestamp date datetime 等编程字符串,而不是js的date 默认值 false

其他的忽略。

连接池 poll 连接参数

连接池把握的核心点,连接有可能超过限制,会进行排队,轮到了才执行

  • acquireTimeout 获取连接超时毫秒,如果连接已经在排队了,时间不算,默认10000
  • waitForConnections 默认true 多的请求排队。如果false超出就报错
  • connectionLimit 最大连接数,默认10
  • queueLimit 排队最大连接数,超出的返回错误,默认0不限制

    连接池事件

pool.on('xxx',()=>{})

  • acquire when a connection is acquired from the pool
  • connection 建立新连接,参数 connection
  • enqueue 进入排队等待
  • release 释放

query(sql, [params], callback)

事务

伪代码

1
2
3
4
5
con.beginTransaction((err)=>{
con.query(xxx,function(){
con.commit()
})
})

ORM Sequelize 部分
ORM Object-relational-mapping 建立映射关系,操作对象。

快速入门

1
yarn add mysql2 sequelize
1
2
3
4
5
6
7
const Sequelize = require('sequelize')
const sequelize = new Sequelize("wp-back", "root", "", {
host: "localhost",
dialect: "mysql",
operatorsAliases: false
});
// 然后定义模型
  • aync.force=true
  • timestamps:false
    define 也可以有 getterMethods, setterMethods 场景 deleteFlag
    有get set方法

数据模型

这里放一个列表


范式

  1. 表的列具有原子性,不可再分解
  2. 一行数据只做一件事,只要重复就该岔开
  3. 只有直接关系,没有间接关系

反范式。

数据库设计原则

三个境界

手中有剑 心中无剑

刚入门数据库设计,范式的重要性还未深刻理解。这时候出现的反范式设计,一般会出问题。

手中有剑 心中有剑

随着遇到问题解决问题,渐渐了解到范式的真正好处,从而能快速设计出低冗余、高效率的数据库。

手中无剑 心中有剑

再经过N年的锻炼,是一定会发觉范式的局限性的。此时再去打破范式,设计更合理的反范式部分。

范式

范式

第一范式

即表的列的具有原子性,不可再分解,即列的信息,不能分解
关系型数据库 自动满足

第二范式

每一行的数据只能与其中一列相关,即一行数据只做一件事。只要数据列中出现数据重复,就要把表拆分开来。
例: 一个人同时订几个房间,就会出来一个订单号多条数据,这样子联系人都是重复的,就会造成数据冗余。我们应该把他拆开来。

第三范式

数据不能存在传递关系,即没个属性都跟主键有直接关系而不是间接关系。

反范式

  • 降低范式适当增加字段
  • 没有冗余的数据库未必是最好的数据库
  • 减少查询时关联
  • 提高查询效率
  • 适度范式 在满足三范式基础上做调整
  • 适用场景
    • 核心业务适用范式
    • 弱一致性需求
    • 空间换时间

经典的还是范式,快速迭代可以反范式

express

简单整理一下express,最好做个代码块

启动项目

1
2
3
4
yarn add axios express bodyparser
node app.js local # 本地测试环境
node app.js debugger # vscode 调试
node app.js # 不带参数共享0.0.0.0

app.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
const express = require("express")
const app = express()
const options = process.argv.splice(2)
let appPort
if (options.includes("local")) {
appPort = 3207
} else if (options.includes("debugger")) {
appPort = 3208
} else {
appPort = 3206
}
const rIndex = require("./routes/index")
app.use("/", rIndex)
app.use("*", r404)
app.listen(appPort, () => {
const url = `http://localhost:${appPort}`
console.log("server start:")
console.log(url)

// 自动打开浏览器
var start =
process.platform == "darwin"
? "open"
: process.platform == "win32"
? "start"
: "xdg-open"
// require("child_process").exec(start + " " + url)
})

router.js

1
2
3
4
const express = require("express")
const router = express.Router()
router.get("/", async function(req, res) {res.json({})}
module.exports = router

今下午纠结

docker的纠结

纠结了一下午,docker-compose 部署遇到了点问题,需求方又在催,哎,急的我。

找了个会docker的陪我看了一会儿,匆匆来,匆匆去。

还是得找技术大牛多的,能够互相鼓励支持,方便我抱大腿。

响应式和媒体查询

啥是媒体查询

1
@media all and (min-width:800px) and (orientation:landscape){}

也可以看 像素比

1
-webkit-min-device-pixel-ratio: 2

图片响应式
声明式的实现。

1
<img src="img/a.png" srcset="img/480.png 480w, img/800.png 800w, img/1600 1600w">

picture
picturefill 兼容插件

1
2
3
4
5
6
7
<picture>
<source media="(min-width:36em)" srcset="img/a.png 768w" />
<source srcset="img/b.jpg 1800w" />
<img src="img/a.jpg">
<source type="image/svg+xml" srcset="logo.svg 480w, logo.svg 800w">
<source type="image/webb" srcset="logo.webp 480w">
</picture>

前端之数据分析

使用 growingIO 的客户:
233 东奥 环球

使用神策的客户:
华图 环球

神策
私有化部署,支付采集,前后打通
支持paas平台

事件分析:浏览,视区停留,app启动,激活,元素点击,退出

课程页
搜索,详情页
报名,支付成功,购买课程 优惠券 点击广告

月注册,月成交
题库转化,转化套餐
网页行为,app行为

webpack

哎呀,这个实践过,还没总结过。

先看优化吧,基础的再说怎么办。

优化

减少转译

就是优化 babel了
对于js,要使用babel,那得指定 include exclude 了

1
loader:'babel-loader?cacheDirectory=true'

并行转换

自然就是别人已经做好的 happyPack 了
通过这个插件可以多线程打包,压榨你的cpu

类库提前打包引入

别人写vue我们就不要打包了,一般也不变,把公共代码抽离单独文件。
entry.vendor
内置插件 webpack.DllPlugin

减少打包的体积

你打包的文件太大了怎么办,记得可视化webpack分析。

思路,不打包,少打包

不打包

分离cdn

少打包

按需加载,页面按需加载。
大型组件,用到啥打包啥
代码用不到的 tree-shaking 掉。

主要是吧,webpack5就要出来了。

原理

  • es6转译。这个babel全家桶搞定了
  • commjs
    哎,这个吧,我觉得没啥。

页面性能

调用

1
performance.getEntriesByType('navigation')

如果要监控异常

基础办法 window.onerror 拦截
拦截不到的 script error. 需要script添加 crossorigin

当然了,需要map方便debig

前端web安全

参考文章

web安全

cors

需要浏览器和后端同时支持。
通过cors跨域的话,发送请求分两种,简单请求,复杂请求预检请求。

简单请求

get head post 方法之一
content-type 常见

复杂请求

会先发一个预检请求,是option 方法,确定是否允许跨域

node中,预检可能会触发回调。所以需要主动过滤 option 204

XSS

是什么

Cross Site Scripting 跨站脚本攻击
用户贡献的内容可能包含js代码,比如评论区里有js,获取cookie等。

  • 反射性。url参数有问题,通过缩短混淆看不出
  • 存储型。存到db,再读取时候执行,更隐蔽

怎么办

  • 轻易不渲染未知的 html v-html

  • 前台后台都要替换实体符号,比如 & < > ' " /

    • 防御 <script>
    • 防御 javascript:
    • 防御 onerror
  • 浏览器自带 xss保护

  • 实在不行,建立tag白名单

  • 引入 xss包 jsxss.com
    继续加强对cookie的限制,比如 http-only js无法修改cookie

    csp

    建立白名单,固定的外部资源才能加载执行
    核心 content-security-policy

CSRF

是什么

Cross site request forgery 跨站请求伪造

场景,别人发给我一个连接,打开之后就自动发了微博动态。这个还是挺常见的。再回想很多垃圾评论都是这么来的。

举例,发布动态是 post,创建一个隐藏的 iframe,post 传递参数,

这个代码构建了一个表单,自动提交,因为 iframe 是隐藏的,target 指向了 iframe,所以页面不会刷新。

1
2
3
4
5
6
<script>
document.write(`<form name target="csrf" method='post' action=""><input></from>`);
var iframe = document.createElement('iframe')
iframe.name='csrf' iframe.style.displya='none' document.body.appendChild(iframe)
setTimeout($().subimt(),1000)
</script>

如果请求是 get,直接 img src 就可以发送请求了。

怎么办

敏感结构post,
多验证权限token
js不让改cookie。 cookie samesite
referer 验证来源
提交之前做验证
referer

中间人攻击

http不安全。
https用了但没关http

Cookies

绕不过 cookies。前端数据存储,同源的请求都会携带。
设置 http-only secuity same-site

iframe

点击劫持,透明iframe

  • 普通页面 top.location === window.location。也不保险
  • http 头 x-frame-options,deny 禁止内嵌。兼容性不错 ie8,推荐

    密码

    哈希算法,雪崩效应,稍微一遍,整体全变。

加密组合,多种加密进行组合。

https 传输,频率限制,前端加密意义有限

sql 注入

直接拼接 sql 语义。

危害:

破解密码,获取数据,删库,拖库

关闭错误输出。模糊化输出。
检查数据类型。
对数据进行转义。
使用参数化查询
使用 orm
nosql 注入和防御

检查数据类型。类型转换。写完整条件。

请我喝杯咖啡吧~