0%

  1. 学习完 go 语言的语法,能够在各种场景下使用 go 语言完成开发。
  2. 学习完 docker ,掌握使用 docker 快速搭建开发环境和根据需求生成镜像的能力。
  3. 学习设计模式,掌握 10 到 15 种设计模式的使用方法和使用场景,了解所有的设计模式并熟悉其优缺点。
  4. 掌握使用 nginx 完成负载均衡和处理大并发时优化的方法,提高对大并发场景的处理能力。
  5. 学习 linux 下常见的命令,能够快速分析日志(文本处理)、设置定时和循环任务(crontab)、服务器调优(定位服务器瓶颈及优化)。
  6. 学习 ES2017 的各种语法,保持对 javascript 的新知识的接触并掌握。
  7. 学习 VueJS 和 webpack,掌握 mvvm 和组件化开发。
  8. 学习 mysql 的索引等优化方法,提高对 sql 的认知水平和使用能力。

golang 中 slice 的便捷操作使排序也更加方便,这是一个使用递归完成的快排。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
func quickSort(arr []int) []int {
if len(arr) <= 1 {
return arr
}
index := len(arr) / 2

var left, right []int
for i, v := range arr {
if i == index {
continue
}
if v <= arr[index] {
left = append(left, v)
continue
}
right = append(right, v)
}
return append(append(quickSort(left), arr[index]), quickSort(right)...)
}

在 HTML 中, 有的位置为了美观设计了最大的行数。然而,由于设备差异和中英文字符的差异,截取字符串指定个数显然不是聪明的选择。这时候,css3 的新特性便可以大展神威了。

单行

1
2
3
overflow: hidden;
text-overflow:ellipsis;
white-space: nowrap;

通过设置禁止换行和超出显示省略号来实现单行文本的溢出控制。

多行

1
2
3
4
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 3;
overflow: hidden;

此方法使用 webkit 的弹性伸缩盒模型实现了多行文本超出自动省略的功能。

兼容性

前者基本上主流浏览器都支持

image.png

后者只在 webkit 浏览器上支持,可以在移动端使用。

在 linux 服务器上,很多资源仍然需要通过代理来获取。比如go中的包大多数都不能够直接安装,因此需要使用 shadowsocks 来启动代理来访问相应网站。

shadowsocks 的安装

1
2
yum install python-setuptools && easy_install pip
pip install git+https://github.com/shadowsocks/shadowsocks.git@master

启动 shadowsocks 客户端

编辑配置文件

1
2
3
4
5
6
7
8
9
10
vim /etc/shadowsocks/config.json
{
"server":"1.1.1.1", #可以使用的ss服务器IP
"server_port":1035, #ss服务器端口
"local_address": "0.0.0.0", # 使用此地址可以允许局域网的连接
"local_port":1080, #本地端口
"password":"password", #连接ss服务器密码
"timeout":600, #等待超时
"method":"rc4-md5", #加密方式
}

启动

1
nohup sslocal -c /etc/shadowsocks/config.json /dev/null 2>&1 &

安装完成后可以使用 socks5 的方式访问代理,但是如果需要使用 http 方式, 还需要安装 privoxy .

安装 privoxy

1
2
3
4
5
6
7
wget https://sourceforge.net/projects/ijbswa/files/Sources/3.0.26%20%28stable%29/privoxy-3.0.26-stable-src.tar.gz
tar zxvf download
cd privoxy-3.0.26-stable
autoheader
autoconf
make
make install

创建 privoxy 用户

1
2
echo 'privoxy:*:7777:7777:privoxy proxy:/no/home:/no/shell' >> /etc/passwd
echo 'privoxy:*:7777:' >> /etc/group

将 privoxy 接收到的代理转发到 shadowsocks

1
echo 'forward-socks5 / 127.0.0.1:1080 .' >> /usr/local/etc/privoxy/config

启动 privoxy

1
/etc/init.d/privoxy start

设置代理

1
2
http_proxy=127.0.0.1:8118
https_proxy=127.0.0.1:8118

然后你就可以通过代理来访问想访问的网址了。例如:

1
go get golang.org/x/net/websocket

初衷

每次重装系统或者新员工入职,都需要重新安装开发环境,而且由于版本问题等会产生各种问题,所以计划使用 docker 来简化安装步骤,统一开发环境。

安装 docker

docker 的安装十分简单,通常很快就能完成。

  • Windows: 下载安装包,安装即可, https://download.docker.com/win/stable/InstallDocker.msi
  • Linux: 执行命令 curl -sSL [https://get.docker.com/](https://get.docker.com/) | sh 即可(附:阿里云安装脚本curl -sSL [http://acs-public-mirror.oss-cn-hangzhou.aliyuncs.com/docker-engine/internet](http://acs-public-mirror.oss-cn-hangzhou.aliyuncs.com/docker-engine/internet) | sh -
  • macOs: brew cask install docker 即可
  • Linux 衍生版本:使用各自的包管理工具即可,如 ubuntu : 执行apt-get install docker.io 即可

获取镜像

使用 docker pull package 来获取镜像。docker 有自己的类似于应用商店的系统–“docker hub”,docker pull 命令可以从上面克隆镜像。但是由于国内访问速度较慢,可以使用国内的镜像地址:

1
2
# 编辑/etc/default/docker文件,添加如下命令
DOCKER_OPTS="--registry-mirror=https://jxus37ad.mirror.aliyuncs.com"

例如我安装一个教程镜像:执行 docker pull learn/tutorial ,便可以下载此镜像到 docker 的本地仓库中

运行镜像

运行镜像使用的主要命令为 docker run , 例如:docker run learn/turorial 便可以运行这个镜像。在命令后可以直接拼接命令,即可在 docker 容器内执行命令。例如

1
docker run learn/tutorial echo "hello world"

输出为 “hello world”。

问题

docker 默认不支持32位操作系统,如果在32位系统下下载镜像,需要指定32位的镜像,例如

1
docker pull 32bit/ubuntu:16.04

为防止出现各种问题,还是建议使用64位的操作系统。

总有更高的云,

也总有更亮的灯,

时光飞转,

我再也没能冲击哪怕一时的荣耀,

只能站直了身子,

等待着别人俯身倾听。

需求

昨天使用 Go 完成了一个小小的爬虫和展示的 web 项目,抓取了5000首古诗文,并能够呈现在自己的网站上。为了避免古诗文的重复,我将古诗文内容进行了 md5 哈希,并作为唯一索引。Go 语言中的哈希并不像 PHP 中那样简单,但是经过实践,也能够快速的理解并使用 Go 语言中的哈希算法。

使用

Golang的加密库都放在crypto目录下,其中MD5库在crypto/md5包中,该包主要提供了New、Write和Sum方法。

  • New 方法用于生成 digest 结构;
  • Write 方法 用于向 digest 结构中写入需要进行哈希的字符串([]byte类型);
  • Sum 方法接收一个参数,将字符串进行哈希并将哈希值拼接在参数后,其内部实现是先使用 checkSum 方法(不对外暴露)进行哈希并将结果拼接在参数后。
1
2
3
4
5
6
type digest struct {
s [4]uint32
x [chunk]byte
nx int
len uint64
}

因此,加密流程如下所示:

1
2
3
c2 := md5.New()
c2.Write([]byte(`hello world`))
c2.Sum([]byte(nil)))

其实有一种更简便的方法,在 md5.go 中,提供了一个 Sum 函数 直接串行了上述方法,因此,上述代码可合并为:

1
md5.Sum([]byte(`hello world`))

上述程序的放回结果为128bit (也就是32位)的16进制数组,如果需要将其转化为 string 类型,需要使用hex.EncodeToString 函数,并需要将数组转化为 slice, 例如:

1
2
3
c1 := md5.Sum([]byte(`hello world`))
fmt.Println(hex.EncodeToString(c1[:]))
//返回“5eb63bbbe01eeed093cb22bb8f5acdc3”

延伸

sha256 方法和 md5 方法的使用方法完全相同,可尝试使用。

1
2
c2 := sha256.Sum256([]byte("hello world"))
fmt.Println(hex.EncodeToString(c2[:]))

遇到问题

在部署 nginx 服务器时,遇到了一个问题,即 nginx 下的 location 有多个条件。

1
2
3
4
5
6
7
8
9
location / {
root /var/www/webapp;
index index.html index.htm index.php;
}

location /go {
root /var/www/webapp;
index index.html index.htm index.php;
}

这时,如果有越来越多的规则难免令人疑惑,究竟是哪一个的优先级更高?

寻求答案

翻阅 nginx 手册,有如下一段话

  1. Test the URI against all prefix strings.
  2. The = (equals sign) modifier defines an exact match of the URI and a prefix string. If the exact match is found, the search stops.
  3. If the ^~ (caret-tilde) modifier prepends the longest matching prefix string, the regular expressions are not checked.
  4. Store the longest matching prefix string.
  5. Test the URI against regular expressions.
  6. Break on the first matching regular expression and use the corresponding location.
  7. If no regular expression matches, use the location corresponding to the stored prefix string.

翻译如下

  1. 测试所有的前缀字符串。
  2. “=” 定义了 URI 和前缀的完全匹配。如果匹配,停止搜索。
  3. 如果 “^~” 表达式和 URI 完全匹配,将会直接返回对应的 location ,其他的常规正则表达式不会再被检查。
  4. 存储最长匹配的常规前缀字符串。
  5. 测试正则表达式。
  6. 在第一次 URI 匹配到正则表达式时,将会终止匹配并使用对应的 location。
  7. 如果没有匹配的正则,就使用第4步中存储的最长的前缀对应的 location。

结论

第一优先级:等号类型(=)的优先级最高。一旦匹配成功,则不再查找其他匹配项。
第二优先级:^~类型表达式。一旦匹配成功,则不再查找其他匹配项。
第三优先级:正则表达式类型~, ~*的优先级次之。如果有多个location的正则能匹配的话,则使用正则表达式最长的那个。
第四优先级:常规字符串匹配类型。按前缀匹配。

参考:

CONFIGURING NGINX PLUS AS A WEB SERVER

最近在项目开发中遇到了一个问题:css 和图片上传后,由于缓存的存在会出现不刷新的情况,项目组让我着手解决,故而写下此篇文章予以记录。

当前的项目结构及处理

image.png

由于audio,font,video不涉及到更新,因此这三个文件夹直接拷贝到新的目标文件夹即可。而图片、 js 和 css 文件则需要生成新的带 md5 的文件并自动替换以完成项目需求。

解决方法

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
var gulp = require('gulp');
var fs = require('fs');
var rev = require('gulp-rev');
var srcReplace = require('gulp-replace-src');

//复制不需要压缩的文件夹,放到 dist 目录
gulp.task("copy", function(){
return gulp.src(['audio/*','video/*', 'font/*'], {base: "./"})
.pipe(gulp.dest('dist/'))
})

//将所有需要添加 md5 的文件改名后放到 dist 目录, 并将文件映射存入到 json 中
gulp.task("version", function() {
return gulp.src(['css/*.css','js/*.js', 'img/*'], {base: "./"})
.pipe(rev())
.pipe(gulp.dest('dist/'))
.pipe(rev.manifest())
.pipe(gulp.dest('dist/'));
});

//根据上一步生成的 json 对 index.html 进行替换
gulp.task("replace", ["version"], function() {
var manifest = JSON.parse(fs.readFileSync('dist/rev-manifest.json').toString("utf-8"));

gulp.src('index.html')
.pipe(srcReplace({
manifest: manifest,
rootPath: './',
basePath: './',
hash: true,
inline: 1
}))
.pipe(gulp.dest('./dist'));
});

gulp.task("default", ["copy", "version", "replace"]);

在现代浏览器中已经逐渐支持 JavaScript 对文件的各种操作,以前必须由后端完成的各种事情也渐渐地可以由前端来完成。传统的 CSV 文件的下载一般都是由后端直接生成 URL,前端访问此 URL来完成下载。现在,这一工作可以完全由前端来负责完成。

数组转化为 CSV

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
var data = [
["张朋", "男", new Date("1994-02-02")],
["李艳", "女", new Date("1993-03-03")],
];

function processRow (row) {
var finalVal = '';
for (var j = 0; j < row.length; j++) {
var innerValue = row[j] === null ? '' : row[j].toString();
if (row[j] instanceof Date) {
innerValue = row[j].toLocaleString();
};
var result = innerValue.replace(/"/g, '""');
if (result.search(/("|,|\n)/g) >= 0)
result = '"' + result + '"';
if (j > 0)
finalVal += ',';
finalVal += result;
}
return finalVal;
};

var csvString = data.map(function(item){return processRow(item)}).join("\n");

CSV 数据转化为 bolb 文件

1
2
//前置的"\uFEFF"为“零宽不换行空格”,可处理中文乱码问题
var blob = new Blob(["\uFEFF" + csvString], { type: 'text/csv;charset=gb2312;' });

获取文件地址并下载

1
2
3
4
var a = document.createElement('a');
a.download = 'name.csv';//这里替换为你需要的文件名
a.href = URL.createObjectURL(blob);
a.click();

参考链接:
How to export JavaScript array info to csv (on client side)?
网页前端导出CSV,Excel格式文件