快速创建Linux用户

连接Linux服务器

1
2
3
4
IP:xxx.xxx.xxx.xxx
端口:一般是22
root用户名:xxxxx
root登录密码:**********

执行创建用户命令

假设需要创建的用户为 tom, 在终端执行: useradd -m 用户名 创建一个 admin 用户和 home 目录

1
$ useradd -m tom

查看用户

执行 compgen -u 查看用户

1
$ compgen -u

为用户设置密码

使用 passwd 用户名 为用户设置密码

1
$ passwd tom

键盘输入密码两次

添加用户到root组

使用 usermod -a -G root 用户名 添加用户到root组, 其中 -a 表示添加,-G 表示添加到组

1
$ usermod -a -G root tom

修改bash外壳

使用命令 chsh -s /bin/bash 用户名

1
$ chsh -s /bin/bash tom

补充说明

家目录

一般用户,家目录是 /home/用户名 ,而 root 用户,家目录是 /root

root登录系统,执行如下命令进入root的家目录:

1
cd ~

进入家目录后执行如下命令获取具体路径:

1
$ pwd

切换用户

执行 su 命令切换用户,从普通用户切到 root 用户需要密码:

1
2
3
4
5
$ su

或者

$ su root

从 root 用户切到普通用户不需要密码:

1
2
3
4
5
$ su 用户名

或者

ctl+d

【前端开发日常 - 2】为项目添加多个Git远程仓库

需求背景

在项目开发中,我们会使用Git来进行版本控制,我们创建的本地仓库有时候需要托管到服务器,如:GitHub码云 等。最近在做的项目代码提交到 码云,而在内网还需要同步到 Gitlab,因此需要将同一份代码关联到两个远程仓库。

解决方案

将本地仓库关联多个远程仓库

核心代码

命令介绍

查看已关联的远程仓库

1
$ git remote -v

 推代码到远程仓库

1
$ git pull <仓库关联命名> <远程分支名>:<本地分支名>

从远程分支拉取代码

1
$ git push <仓库关联命名> <本地分支名>:<远程分支名>

取消本地目录下关联的远程库

1
$ git remote remove origin

关联方式

这里有两种关联远程仓库的方式,用来应对不同的需求。

方式一

新增关联,每个链接单独 push 代码

添加一个远程库,名字不是 origin,而是自己定义的关联名称:

1
$ git remote add <仓库关联命名> <远程仓库地址>

推拉代码

1
2
$ git pull <仓库关联命名> <远程分支名>:<本地分支名> # 推代码到远程
$ git push <仓库关联命名> <本地分支名>:<远程分支名> # 从远程分支拉取代码

方式二

同一个关联添加多个远程地址,同时推送到多个仓库

增加一个远程库,名字依旧是 origin

1
$ git remote set-url --add origin <远程仓库地址>

推拉代码

1
2
$ git pull origin <远程分支名>:<本地分支名> # 推代码到远程
$ git push origin <本地分支名>:<远程分支名> # 从远程分支拉取代码

写 JavaScript 组件(库)的小细节

开发一个库要考虑那些?先来快速看一下:

  • 设置 GitHub
  • 配置 npm 并且创建 package.json
  • 创建组件库并添加依赖
  • 推代码到 GitHub
  • 发布 NPM 包
  • 发布一个版本到 GitHub
  • 发布一个新版本到 NPM
  • 发布一个 beta 版本
  • 设置好单元测试(如Mocha 和 Chai)
  • 进行单元测试
  • 自动管理发布版本(semantic-release)
  • 提交规范(如commitizen)
  • 提交新特性(如commitizen)
  • 持续集成(如TravisCI)
  • 提交前自动测试(如ghooks)
  • 代码覆盖率统计(如istanbul)
  • 代码覆盖率检查
  • 代码覆盖率报告分析
  • README(如添加徽章等)
  • 添加 ES6 支持
  • 测试支持 ES6(Mocha 和 Babel)
  • 限制编译分支
  • 浏览器版本编译

下文的内容不会对上面的点做介绍,只在从一些容易忽略的小点进行介绍。

任务明确

明确写的库或组件目的是什么,一个库应该专注于处理好特定的任务。比如 React 和 Vue 都是围绕着DOM操作来进行抽象的,又比如 Angular 专注于DOM抽象、HTTP网络、依赖注入等并且提供一个完整的应用框架。

先来看下面这个库,用来判断是否存在用户 home 目录,引入了 2 个库,并且只有 1 行有效代码,这适得其反:

1
2
3
4
'use strict';
var osHomedir = require('os-homedir');
var osTmpdir = require('os-tmpdir');
module.exports = osHomedir() || osTmpdir();

再来看 egg-jwt 的这个中间件,只是单纯的使用了 koa-jwt2 并且设置了参数而已,这也是为什么我直接使用 koa-jwt2 的原因:

1
2
3
4
5
6
7
'use strict';

const koajwt = require('koa-jwt2');

module.exports = options => {
return koajwt(options);
};

总的来说就是一个库要解决实际问题,而不是没有意义或是造成繁琐。

向下兼容

编写组件时,应尽量考虑向下兼容,不然会造成使用者的很多疑惑,npm 在安装时会自动决定版本:

  • ~ 会匹配最近的小版本(修订版本)依赖包,比如 ~1.2.3 会匹配所有 1.2.x 版本,但是不包括 1.3.0
  • ^ 会匹配最新的大版本(次版本)依赖包,比如 ^1.2.3 会匹配所有 1.x.x 的包,包括 1.3.0 ,但是不包括 2.0.0

虽然 npm 现在引入了 package-lock.json 这样,但是任然没有办法解决安装新包导致的版本问题。

即使你遵循了 semver(语义化版本规范)发布了对应的主版本号,也要尽量避免 breaking changes (破坏性升级),如果你正在使用一个库并发现了 bug,并且注意到 bug 在以后的主版本中得到了修复,除非库作者维护了多个主要版本,否则你可能需要重构你的代码来使用最新的主版本。遵循 semver 列出的设计,向下兼容应该更容易。

关于语义化版本规范版本号格式,下面引用文章:semver 语义化版本规范 中的一段介绍:

主版本号[MAJOR].次版本号[MINOR].修订号[PATCH],版本号递增规则如下:

  1. 主版本号:当做了不兼容的 API 修改,
  2. 次版本号:当做了向下兼容的功能性新增,
  3. 修订号:当做了向下兼容的问题修正。

先行版本号及版本编译信息可以加到“主版本号.次版本号.修订号”的后面,作为延伸。

当主版本号升级后,次版本号和修订号需要重置为0,次版本号进行升级后,修订版本需要重置为0。

轻量和灵活

尝试使用较少的代码解决问题,可以减少向下兼容成本和 API 的提供。轻量灵活的组件让使用者少面临一些问题,并且节省带宽。

举个栗子:

假设你在开发一个下拉组件要支持 auto-complete,与其考虑如何让组件发送请求、展示数据,不如考虑如何去支持 auto-complete。下面的代码是一个例子:

1
2
3
4
5
6
7
8
let dropdown = new Dropdown();
input.addEventListener('input', (e) => {
let value = e.target.value;
fetch(`/search?value=${value}`).then(res => {
dropdown.setItems(res);
dropdown.showList();
});
});

使用者只需要监听 input 的内容,发送请求到他们的服务器获得结果,然后调用组件的 setItemsshowList

来展示。如果只需要本地自动补全,可以将请求本身换成一个本地的数据查找即可。

避免代码隐患

多考虑组件的输入输出会存在的隐患,考虑使用者的使用场景。

举个栗子:

假设你在创建一个组件,使用者在使用时需要传递一个对象数组,数组每项包括 titlevalue ,当他们点击每一项时,将传递对应项的 titlevalue 属性到 callback 方法里面。

那么问题来了:

假如使用者传递了你不支持的 key 将如何?这个 key 会传递到给定的 callback 吗?假设未来你将使用到这个 key 呢?你在组件里是使用同一个对象还是克隆的对象?假设使用者传递了一个数组并且在别处修改了这个数组会怎么样?组件需要因为数组的变化而更改显示吗?

这都是非常容易忽略的问题,但是却很重要。这些异常疏漏很容易产生 bug,如果你修复了这些 bug(比如通过克隆使用传参),这将导致他人的应用面临崩溃的风险,因此在组件发布之前需要尽力排查出这些问题。

思考组件的细节

输入输出

一个组件通常都需要设计合理的 inputoutput ,在编写组件时,需要考虑恰当的输入值和类型,是否需要回调,并且对这些传入的值进行类型的校验/限制,因为你无法强制使用者传或是不传,也不能确定强制用户怎么传递。

默认的参数

尽可能的为组件本身的属性、数值设置默认值,当用户没有传递任何值时,确保组件的正常工作。

React 中的 dumb组件 和 smart组件

在react中,只会接收props,根据props进行渲染的组件称为Dumb组件。Dumb组件不依赖除了 React.js 和Dumb组件以外的内容,Dumb组件是最纯粹的,可复用性最好的组件。单靠Dumb组件无法构建应该程序,因为它们除props外,不依赖其他外部的内容,因而无法获取数据。这就需要另一种组件,它们非常“聪明”,专门从事数据相关的应用逻辑,如发送XMLHttpRequest,这种组件称为Smart组件。

贴合原生DOM的属性设置

使用者会遵循习惯和常识来使用你的组件,在设计输入属性和回调函数时,应尽量语义化、标准化。并且贴合原生 DOM,比如设置一个 Input 组件,我们考虑的属性应该是 valueonchangeplaceholder 等,这些都是使用者非常熟悉的,可以本能的来使用组件。

提供可定制的方法

很多使用者在使用组件时,都需要可以定制样式或特定的结构,这需要组件开发阶段考虑进来。

简化 HTML 和 CSS

首先,为你的 HTML 样式增加合适的命名空间,这将确保你的组件样式不会影响到其它组件,也给了其他使用者一个清晰的使用和定制方向。

BEM 是一种前端命名方法论,主要是针对 CSS,意思是块(Block)、元素(Element)、修饰符(Modifier)的简写。这种命名方法让 CSS 便于统一团队开发规范和方便维护。(例子: MyComponent-element_modifier_value)

举个栗子:

HTML

1
2
3
4
5
6
7
8
9
<button class="button">
Normal button
</button>
<button class="button button--state-success">
Success button
</button>
<button class="button button--state-danger">
Danger button
</button>

CSS

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
.button {
display: inline-block;
border-radius: 3px;
padding: 7px 12px;
border: 1px solid #D5D5D5;
background-image: linear-gradient(#EEE, #DDD);
font: 700 13px/18px Helvetica, arial;
}
.button--state-success {
color: #FFF;
background: #569E3D linear-gradient(#79D858, #569E3D) repeat-x;
border-color: #4A993E;
}
.button--state-danger {
color: #900;
}

优点

模块化:

  • 块样式永远不依赖于页面上的其他元素,因此你不会遇到级联问题。
  • 你还可以将已完成项目中的块转移到新项目。

可重用性:

  • 以不同方式组合独立块,并智能地重用它们,减少了你必须维护的 CSS 代码量。
  • 有了一套样式指南,你可以构建一个块库,使你的 CSS 超级有效。

很多组件库往往提供了复杂的组件效果,个人倾向于用最少的样式,最少的层级来让你的组件工作,因为要定制/覆盖组件样式对于使用者来说是非常麻烦的事情,往往导致很多问题。

考虑为使用者提供一些 API 来注入他们的 DOM,而不是只提供特定的配置项。

回到前面提到的下拉组件,比起提供图标,更好的方式是提供方法给用户返回 DOM 插入到每一项,这样只需要提供一个方法,就能实现灵活定制列表图标

跟进浏览器标准

Web 开发技术日新月异,新的技术总是带来更多的便利,在使用新的特性时,需要考虑兼容性。新的标准被提出,旧的标准也可能移除,现在的代码可能在未来收到影响,因此需要跟进浏览器标准,以确保自己的组件库能够运行在用户的平台。

减少不必要的依赖

  • 是否必须使用lodash?
  • 是否能使用原生DOM API来代替 jQuery?
  • 是否能够使组件支持多个前端库,而不仅仅是 React?

当你引入依赖,意味使用者需要自己清楚这些依赖的稳定性、大小、许可权等等问题,是否对自己的现有代码造成影响。减少依赖可以让自己的组件更通用,适配性更强,更适合于在不同的前端技术栈里面封装/使用。

致力于最小

当在写一个组件时,需要将库的体积尽可能的减小。浏览器执行 JavaScript 时需要解析编译,100KB的 JavaScript 和 100KB 的图片是完全不一样的,不管是否使用 gzip 压缩或者 HTTP2,JavaScript 执行时都需要解析编译成机器语言,这些都需要耗费时间。

如果是使用 ES6 和 Babel,即使写的代码变少了,最终生成的代码也是巨量的,这点也要考虑进去。

导出版本

ES6

模块的引入不光有传统的 AMD(异步模块定义)规范 和 CommonJS 规范,还有现在的 ES6 模块定义,可以考虑导出支持 ES6 import 的库,让使用者决定以哪种方式来引入,并且支持 tree-shaking 编译。

UMD

UMD(Unified Module Definition 通用模块定义) 让我们可以在浏览器使用 <script> 引入代码也可以使用 require 引入,但是UMD打包出来的文件会添加很多可能不会用到的代码,因此导出版本时也需要考虑到这一点。一些注意事项可以参考:How to write and build JS libraries in 2018

关于模块定义,可以参考 认识AMD、CMD、UMD、CommonJS 一文。

测试用例

在组件开发中,测试用例是必要的,这可以让其他使用者放心使用你的组件库而不需自己测试,也为自己提供机制确保不会破坏向下兼容。

在写测试用例的时候,不要只做简单的检查,需要详细的检查确保功能按照预期工作,产生的异常、适配等问题需要反复测试。

当你修复了一个 bug,也需要写一个测试用例来验证 bug 不会复现,目的就是减少异常的产生。

学习使用许可

MIT 是 JavaScript 开源社区标配的一种许可标准,如果使用了像 GPL(General Public License 通用公共许可证) 这种模棱两可的许可,可能会造成一定的歧义。这将会影响你的组件库的使用量,应尽量为自己和使用者减少麻烦。

关于开源协议,详情查看:五种开源协议的比较(BSD,Apache,GPL,LGPL,MIT) ,这里摘抄一段:

MIT(MIT)

MIT是和 BSD一样宽范的许可协议,作者只想保留版权,而无任何其他的限制,也就是说,你必
须在你的发行版里包含原许可协议的声明,无论你是以二进制发布的还是以源代码发布的。

总结

上面是一些关于编写JavaScript库或组件的思考,要做的东西很多,但目的都是为了写更少的代码,让更多人受益。

参考资料

了解 cookie 和 session

首先来了解 HTTP (HyperText Transfer Protocol 超文本传输协议) 的几个特性:

  • HTTP 建立于客户端-服务端(client/server)模型之上,浏览器发送请求,Web服务器接收请求后向客户端发送响应信息

  • HTTP 是无状态的(stateless)协议,每一次传输都是独立的,互不影响。

  • HTTP 是一个应用层 (application layer) 协议,在传输层(transfer layer)协议之上,使用(TCP)作为传输层协议。

  • 客户端请求服务端使用不同的请求方式(包括:GET、POST、DELETE、PUT 等)。

  • HTTP 定义了服务端状态码返回给客户端(如:200、404、500)。

  • HTTP 支持设置头部 headers,(包括:Cache-Control、Content-type 等)。

http请求报文:

http_message

HTTP 是无状态的,意味着每次页面加载、每次请求都是独立的事件,和前后的事件没有关联。客户端请求服务之后,服务端不能区分发起 HTTP 请求的用户以及用户在网站的状态等,Cookie 和 Session 使 HTTP 能够维持状态,让网站能够记住用户的一些信息。

Cookie 通常是由 浏览器 保存在用户电脑的小文本文件,经过浏览器转换成包含用户网站上的信息的文本,在浏览器发送 HTTP 请求的时候会把这些信息加在请求头中发送给服务端,服务端再根据 Cookie 来判断不同用户的信息。

Session 是 服务端 存储的用来标识用户信息的数据,当用户访问网站时,服务器会为这个用户创建一个唯一的 session id,服务器会把这个id通过 cookie 的形式传给浏览器,浏览器接收 cookie 之后,请求就能携带这个 cookie 访问服务器,通过这个session id 服务端就能够对访问的用户进行辨别。

cookie_and_session

举个栗子:

商店发的会员卡(cookie),它记录了用户的信息(identification),并且是由商店(服务器)发给用户(浏览器),每次用户去商店消费都会携带着会员卡,由于商店管理了自己发布的会员卡信息,可以通过用户会员卡ID(session id)找到该用户的信息。

Session cookies 和 Persistent cookies

  • 会话 cookie(Session cookies)在浏览网页时被创建,通常放在活动内存,会话结束时(浏览器关闭)会被删除。
  • 持久化 cookie(Persistent cookies)浏览网页是被创建,并且没有失效之前,始终存在于浏览器的 cookie 存储目录,在到达失效日期时会被删除。

通常 cookie 都会包含以下内容:

  • Cookie 来源的服务器名称
  • Cookie 保存的时间
  • 随机生成的唯一的数值

Cookie 是一个很小的文本文件,通常会被命名为类似 abc@example.com.txt 的文件,如果打开这些文件,可以看到类似如下的内容:

1
2
HMP1 1 example.com/ 0 4058205869
384749284 403847430 3449083948 *

Google Chrome 浏览器使用 SQLite 文件存储 cookie ,默认存储在:

1
C:\Users\<your_username>\AppData\Local\Google\Chrome\User Data\Default\

并且 Cookie 的值被加密了,因此无法直接打开。

  • 不设置 cookie 过期时间,cookie 会在会话结束后销毁
  • 持久 cookie 无法改成会话 cookie,除非删除再重新创建 cookie
  • 将 cookie 的 domain 选项设置为主域名,子域名可以携带该 cookie 的发送到服务器

如何使用 cookie?

服务端

服务器通过响应头 Set-Cookie 来告诉浏览器创建一个 cookie,Set-Cookie 的值一个字符串,其格式如下:

1
Set-Cookie: <name>=<value>[; expires=<date>][; domain=<domain>][; path=<path>][; secure][; httponly]

上面的格式中,“[]” 内部都是可选值,他们分别有如下作用:

  • <name>=<value> - 储存的字符串,会被浏览器携带发送回服务器,通常是一个 name=value 格式的字符串
  • expires - Cookie 的过期时间,不设置的话,创建的 cookie 在会话结束后销毁,格式为 DD-Mon-YYYY HH:MM:SS GMT
  • domain - Cookie 被设置的域,只有向该域发送 HTTP 请求时才会携带对应的 cookie
  • path - Cookie 被设置的路径,之后向该路径发起请求才会携带对应的 cookie
  • secure - 一个 boolean 标记 cookie 是否只能通过 HTTPS 请求发送至服务器。
  • httponly - 告诉浏览器该 cookie 不能通过 JavaScript 访问,可以阻止跨站脚本攻击(XSS)窃用 cookie。

可以返回多个 Set-Cookie 头来设置多个 cookie:

1
2
Set-Cookie: name=moyufed; path=/; expires=Mon, 26 Jul 2021 11:10:02 GMT; domain=localhost
Set-Cookie: name2=moyufed2; path=/; expires=Mon, 26 Jul 2021 11:10:02 GMT; domain=localhost

客户端

JavaScript 通过 document.cookie 进行 cookie 的操作,但是仅限于非 httpOnly 的情况:

获取 cookie:

1
document.cookie

创建或修改 cookie:

1
document.cookie="name="+username;

在浏览器发送请求时,会将 cookie 添加到请求头中,如果有多个 cookie,将以分号和空格分隔,cookie 的格式如下:

1
Cookie: name=moyufed; name2=moyufed2

Koa 已经提供了从通过上下文(ctx)直接读写入 cookie 的方法,分别为:

  • ctx.cookies.get(name, [options]) - 通过上下文读取 cookie
  • ctx.cookies.set(name, value, [options]) - 通过上下文写入 cookie
1
2
3
4
5
6
7
8
9
10
11
12
ctx.cookies.set(
'name',
'moyufed',
{
domain: 'localhost', // 设置 cookie 的域
path: '/', // 设置 cookie 的路径
maxAge: 24 * 60 * 60 * 1000, // cookie 的有效时间 ms
expires: new Date('2020-10-10'), // cookie 的失效日期,如果设置了 maxAge,expires 将没有作用
httpOnly: false, // 是否要设置 httpOnly
overwrite: false // 是否要覆盖已有的 cookie 设置
}
)

上面的代码没有设置 httpOnly,通过 document.cookie 可以获取到 "name=moyufed",在访问 '/' 路径时,可以看到请求头里面携带了设置的 cookie。事实上 koa2 使用了 npm 的 cookies 模块来读写 cookie,上面的配置都可以从 cookies 源码查看。

如何使用 session?

Session 存储在服务端,不会在网络中进行传输,但服务器产生的 session id 会以 cookie 存在客户端。

用户通过浏览器访问 web 站点,服务器会产生一个唯一的 session id,通过 Set-Cookie 响应头将其发送到浏览器,之后浏览器发送的请求都会自动携带这个 cookie,服务器根据 cookie 获取到的 session id 来获得存储在服务端的用户的信息。

用户信息储存的方式可以是内存(Redis)或数据库。

在 koa 中使用 session

Koa2 没有提供直接设置 session 的操作,但也有很多用于操作 session 的中间件,这里将使用 koa-session-minimal 中间件来处理 session,并且还将使用 redis 作为储存介质。同样,也有 koa-redis 来为 koa 的 session 中间件提供 redis 储存。

关于 redis 的安装可以查看 【前端开发日常 - 4】Windows安装Redis及简单使用

安装中间件:

1
$ npm install koa-session-minimal koa-redis

示例代码:

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
// app.js

const Koa = require('koa'); // 引入koa
const Router = require('koa-router');

const session = require('koa-session-minimal');
const redisStore = require('koa-redis');

const app = new Koa(); // 创建 koa 应用
const router = new Router(); // 使用 koa-router

// 存放 sessionId 的 cookie 配置,根据情况自己设定
let cookie = {
maxAge: 60 * 60 * 1000, // cookie 有效时长(ms)
expires: '', // cookie 失效时间
path: '', // 写 cookie 所在的路径
domain: '', // 写 cookie 所在的域名
httpOnly: true, // 是否只用于 http 请求中获取
overwrite: true, // 是否允许重写
secure: '',
sameSite: '',
signed: true,
}

app.use(session({
key: 'SESSION_ID', // 使用 SESSION_ID 来作为 redis key 的前缀
store: redisStore(),
cookie: cookie // 设置 session id 储存的 cookie
}))

router.get('/', async ctx => {
ctx.body = 'Hello world!';
})

router.get('/get', async ctx => {
// 读取和修改 session 信息
ctx.session.count = ctx.session.count + 1
ctx.body = ctx.session;
})

router.get('/set', async (ctx) => {
// 设置 session
ctx.session = {
id: Math.random().toString(36).substr(2), // 随机 id
count: 0
}
ctx.body = ctx.session;
})

app.use(router.routes()).use(router.allowedMethods());

// 启动服务监听本地3000端口
app.listen(3000, () => {
console.log('应用已经启动,http://localhost:3000');
})

上面的代码中,通过 require(); 引入了 koa 的中间件,并且在使用时传递了设置信息,通过访问 http://localhost:3000/sethttp://localhost:3000/get 分别设置和获取 session。当客户端访问对应 URL 时,服务端将 session 数据进行存储,而在浏览器访问 http://localhost:3000/get 将会看到 session 存储的数据:

1
{"id":"7zcj87rsyd","count":1}

通过查看请求,可以看到中间件管理了 session id 的产生以及 cookie 的设置,它会产生唯一的 SESSION_ID 返回给浏览器:

session_id_response

而在 redis 中也能够看到存储的 session 数据:

session_data_redis

总结

通过前面的介绍,我们了解到:

  • Web 开发中引入 cookie 和 session 的原因(HTTP 的无状态)
  • Cookie 和 session 的区别
  • Cookie 包含的内容和用法
  • Cookie 与 session 的工作方式

参考资料

https://www.allaboutcookies.org/cookies/

https://www.privacypolicies.com/blog/browser-cookies-guide/

https://stackoverflow.com/questions/31021764/where-does-chrome-store-cookies

【前端开发日常 - 4】Windows安装Redis及简单使用

需求背景

目前在使用阿里 Egg.js 开发后台应用,考虑到一些高并发的接口会经常调用数据库查询,因此增加Redis作为服务端缓存。

解决方案

  1. 安装 Redis,由于系统是 Windows7,因此需要下载对应 Windows 的版本,下载地址:https://github.com/MicrosoftArchive/redis/releases

  2. 简单配置 Redis 启动,为 Redis 的连接增加密码,以确保安全性

核心代码

安装 Redis

访问上面的【下载地址】,选择需要的版本,展开 Assets 目录,可以选择 .msi 文件或 .zip 文件下载。如果下载 .msi 文件,可以直接执行安装(勾选对应的复选框),安装通过之后,Windows 会直接将 Redis 写入服务。

如果下载 .zip 文件,还需要对文件进行解压和安装,需要在 redis 目录执行命令:

1
$ redis-server.exe --service-install redis.windows.conf

上面的命令会安装一个Windows服务,关于服务的命令有:

1
2
3
4
5
6
7
$ redis-server.exe --service-uninstall # 卸载服务

$ redis-server.exe --service-start # 开启服务

$ redis-server.exe --service-stop # 停止服务

$ redis-server.exe --service-name name # 重命名服务

检查 Windows 服务

以 Windows7 为例,可以进入 控制面板\所有控制面板项\管理工具 找到 【服务】,点开之后,在服务列表里面找到 Redis。

Redis 启动和关闭

安装好之后,我们可以通过服务启动和关闭 Redis 了,我们可以查看系统的任务管理器,检查是否启动了 redis-server,下面是 redis-server 的启动和关闭命令:

1
2
$ redis-server.exe  --service-start # 启动
$ redis-server.exe --service-stop # 关闭

使用 cli

确认 redis-server 启动之后,我们可以执行 redis 目录里面的 redis-cli.exe 文件,这样就可以连接上 Redis 了。当然,我们也可以通过命令行 CMD 来链接 Redis。

可以直接进行 Redis 存取了:

1
2
3
4
5
6
$ redis-cli.exe -h 127.0.0.1 -p 6379
127.0.0.1:6379> set firstKey "moyufed"
OK
127.0.0.1:6379> get firstKey
"moyufed"
127.0.0.1:6379>

增加密码

在 Redis 的安装目录中,有 redis.windows.conf 、redis.windows-service.conf 两个文件,我们使用记事本打开(推荐Notepad++),找到需要设置密码的行,可以 Ctrl + F 查找 “requirepass” 的所在的行,分别设置 Redis 密码(去掉前面的 #),例子:

1
requirepass moyufed

使用 Redis

修改好之后重启 redis-server ,此时连接 Redis 之后进行 Redis 存取需要登录,例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
Administrator@WIN-1706081829 C:\Users\Administrator
$ redis-server.exe --service-stop
[42636] 25 Feb 18:42:53.622 # Redis service successfully stopped.

Administrator@WIN-1706081829 C:\Users\Administrator
$ redis-server.exe --service-start
[38828] 25 Feb 18:42:58.576 # Redis service successfully started.

Administrator@WIN-1706081829 C:\Users\Administrator
$ redis-cli.exe -h 127.0.0.1 -p 6379
127.0.0.1:6379> set firstKey "moyufed"
(error) NOAUTH Authentication required.
127.0.0.1:6379> auth moyufed
OK
127.0.0.1:6379> set firstKey "moyufed"
OK
127.0.0.1:6379> get firstKey
"moyufed"
127.0.0.1:6379>

参考文档

Window配置Redis环境和简单使用:https://www.cnblogs.com/wxjnew/p/9160855.html
Windows下Redis安装配置和使用注意事项:https://www.cnblogs.com/LMJBlogs/p/11550170.html

【前端开发日常 - 7】简单粗暴,在React中快速使用Mobx

需求背景

最近在做 React 项目,是一个简单的编辑页,刚开始没有考虑到复杂的场景,随着新的想法加入,现在需要增加多个页面,因此使用了 react-router ,为了在每个页面之间共享数据,实现状态管理,决定在项目中加入 Mobx 。

解决方案

1、安装 mobx 和 mobx-react ;
2、创建 store 并且使用 ;
3、使用@装饰器,在 【前端开发日常 - 3】让create-react-app支持@装饰器语法 文章中有介绍。

更多

【前端开发日常 - 3】让create-react-app支持@装饰器语法

需求背景

目前在做的一个 react 项目是使用 create-react-app 创建的,我需要在里面使用 mobxmobx-react 管理状态,mobx-react 支持使用装饰器的方式来书写,而 create-react-app 目前还没有内置的装饰器支持,所以在启动项目时会报错。

1
Support for the experimental syntax 'decorators-legacy' isn't currently enabled

解决方案

使用 react-app-rewired 修改 create-react-app 的配置,使其支持装饰器语法。

此工具可以在不 ‘eject’ 也不创建额外 react-scripts 的情况下修改 create-react-app 内置的 webpack 配置,然后你将拥有 create-react-app 的一切特性,且可以根据你的需要去配置 webpack 的 plugins, loaders 等。

更多

通过rel=preload进行内容预加载

更多详情可以参考,参考 MDN文档

需求背景

最近遇到的问题:

  • 一个页面加载主要逻辑 main.js ,该文件很大,设计很多业务代码,并且依赖部分 JavaScript 插件,在 main.js 执行之前需要确保 JavaScript 插件加载完成。
  • 需要确保 main.js 以较快的速度加载,不能因为 js 文件的加载顺序影响首页渲染时间。

更多