Vim 全局命令 g

全局命令 :g 在 Vim 中有着意想不到强大的功能。当想要在整个文件中对于匹配的行或者不匹配行进行一些操作时,应该第一时间想到这个 :g 命令。

:[range]global[!]/{pattern}/{command}

简写可以写成

:[range]g/pattern/command
  • [range] 指定文本范围,默认为整个文档
  • pattern 在范围 range 内的行如果匹配 pattern,则执行 command
  • ! 表示取反,也就是不匹配的行,也可以使用 vglobal
  • command 默认是打印文本

整个命令可以理解成,在 range 范围内匹配 patter 的行执行 Ex command。所有的 Ex command 可以使用 :help ex-cmd 来查看。

常用的 Ex command 可以参考如下例子:

  • d 删除
  • m 移动
  • t 拷贝
  • s 替换

举例

范围匹配

比如在 20 行到 200 行之间,每一行下插入空行

:20,200g/^/pu _

删除匹配的行

最简单的使用

:g/pattern/d

会删除 pattern 批量的行,再比如

:g/^$/d

可以用来删除空白行。

删除不匹配的行

匹配使用 :g ,而不匹配有两种写法:

:g!/pattern/d
:v/pattern/d

:v:in(v)erse 的缩写,如果为了记忆的话,可以记住 inverse。

删除大量匹配行

Vim 在删除操作时,会先把要删除的内容放到寄存器中,假如没有指定寄存器,会默认放到一个未命名的寄存器中,对于要删除大量匹配行的行为,可能导致 Vim 花一些时间处理这些拷贝,避免花费不必要的时间可以指定一个 blackhole 寄存器 _

:g/pattern/d_

移动匹配的行

将所有匹配的行移动到文件的末尾

:g/pattern/m$

复制匹配的行

将所有匹配的行复制到文件末尾

:g/pattern/t$

复制到 register a

Vim 每个字母都是一个寄存器,所以使用全局命令也可以将内容复制到某一个寄存器,比如 a

qaq:g/pattern/y A
  • qaq 清空寄存器 a,qa 开始记录命令到a寄存器,q 停止记录
  • y A 将匹配的行 A (append) 追加到寄存器 a 中

存放到 a 寄存器之后就可以使用 "ap 来粘贴使用或者其他操作了。

反转文件中的每一行

just show the power of :g

:g/^/m0

:g 命令一行行匹配,匹配第一行时将第一行 m0 放到文件顶部,第二行放到文件顶部,当跑完一遍之后整个文件的每一行就反转了。

在匹配行后添加文字

使用 s 命令可以实现,同样使用全局 g 命令也可以实现同样的效果

:g/pattern/s/$/mytext

这里使用到了 s 命令, substitute 命令,可以使用 :help :s 来查看。

reference


2017-10-29 Vim , Regex , Linux

kibana query syntax

Kibana 的查询语法基于 Lucene 的查询语法,他允许 boolean 值,通配符,过滤器等等操作。

字符串查询

通常一个查询会包含一个或者多个单词或者组合。一个简单的查询语句就是用引号包含的一组词,比如 “search demo”.

如果不包含双引号,Kibana 会单独的去匹配每一个词。

正则表达式查询

大部分正则表达式是允许匹配部分字符的,然而在 Lucene 中,正则表达式用来匹配整个字符串,比如 abcde 这个字符串

  • 使用 ab.* 能够匹配
  • 但是使用 abcd 是不能匹配的

正则表达式中,有一些保留字符

. ? + * | { } [ ] ( ) " \

这些字符如果出现在表达式中都需要进行转义,比如 \* ,或者 \\

这些符号的含义和正则表达式一致

  • . 用来表示任意字符
  • ? 用来表示前面的字符重复一次或零次
  • + 表示前面的字符重复一次或多次
  • * 表示前面的字符重复零次或多次
  • {n} 表示重复n次
  • {n,m} 表示重复n到m次
  • () 表示 group, 组合其他使用
  • | 表示 OR 或者,(http|https) http 或者 https 匹配
  • [] 表示括号中的任意一个

更多的关于正则表达式的内容可以参考任意一本关于正则的书。

补充,在 Kibana 中如下字符都需要转义

+ - = && || > < ! ( ) { } [ ] ^ " ~ * ? : \ /

比如查询 (1+1)=2 需要使用 \(1\+1\)\=2

可选表达式

Lucene 中还能够开启一些扩展操作。

Complement 模式

比如 ab~cd 可以表示字符串以 ab 开始接着跟随一个任意长度非c字符,以d结尾的字符串。

Interval

使用 <> 来匹配数字范围, 比如 foo<1-100> 可以匹配string foo90 却不能匹配 foo101

Intersection

符号 & 用来连接两个 patterns 两个正则表达式都需要匹配

Any string

符号 @ 用来匹配所有,和 Intersection 联合使用可以用来表示,匹配所有除了。

比如 @&~(foo.*) 用来匹配所有字符,除了以 foo 开头的字符

范围查询

范围查询用来查询一定范围的匹配,比如

ResponseTime: [10 TO *]

用来查询请求时间大于等于 10 ms 的,或者使用 ResponseTime: {10 TO *} 来匹配大于 10 ms 的。

方括号可以表示包括,花括号不包括,所以 [10 TO 50} 表示 需要 10<=value<50

也可以简化写成

age:(>=10 AND <50)

这样

Boolean 查询

逻辑运算 AND、OR、NOT 可以用来组合查询语句,这三个运算符必须 大写 ,更多内容可以查看 Lucene 语法。

  • + 搜索结果中必须包含此项
  • - 不能含有此项

字段名称搜索

比如需要查询 statusactive 的内容,可以

status:active

近似搜索

在短语后面加 ~ 可以搜到被隔开或者顺序不同的单词。

比如 “where select”~5, 表示 select 和 where 中间可以相隔5个单词。

reference


2017-10-29

每天学习一个命令:代码搜索工具 ack-grep

ack 是一个代码搜索工具,作者 厌烦了 grep 复杂的语法,所以创造了 ack 来解决痛点。ack 使用 Perl 语言开发,使用友好,速度快。

安装

sudo apt-get install ack-grep

使用

文本搜索

默认情况下 ack-grep 会搜索当前目录下所有文件内容,只要包含关键字就会输出。

ack-grep keyword
ack-grep -l keyword     # 只显示文件名
ack-grep -i keyword     # 忽略大小写
ack-grep -w keyword     # 强制要求 PATTERN 匹配整个单词

查找文件

可以代替 find 加 grep,其实 ack 的 -f 选项表示的是打印所有将要被搜索的文件,事实上不会执行搜索,如果后面加 PATTERN ,那么就在路径中搜索文件名。-g 选项表示的是搜索当前路径下的符合 PATTERN 的文件。

ack-grep -f filename
ack-grep -g file*

过滤文件

可以使用 --python 选项来指定在 python 文件中搜索

ack-grep --python keyword

reference


2017-10-26 ack , linux , command

Nginx 反向代理 Google 配置

使用编译安装 Nginx,将 ngx_http_substitutions_filter_modulengx_http_google_filter_module 两个模块编译进 Nginx。具体内容可以参考安装篇。

对于 Nginx 基本设置可以参考 配置篇 .

这篇主要演示 Nginx 作为一个反向代理服务器的基本设置。

Nginx 反向代理最重要的一个配置就是 proxy_pass ,该配置接受一个参数, URL ,也就是 Nginx 转发的目的地。Nginx 会自动将请求的 URI 替换为 proxy_pass 配置的 URI。

location /uri {
    proxy_pass http://localhost:8083/newUri;
}

常用配置

反代相关配置

反向代理的常用配置选项

Directive Explanation
proxy_connect_timeout 向上游服务器请求超时时间
proxy_cookie_domain 将请求头中 Set-Cookie 头内容替换成新域名
proxy_cookie_path 替换 Set-Cookie 中路径
proxy_headers_hash_bucket_size 请求头名最大size
proxy_headers_hash_max_size 从上游服务器接收到的所有 headers 总量
proxy_hide_header 一组不会被传给 client 的 headers
proxy_http_version 和上游服务器通信使用的 HTTP 协议版本
proxy_ignore_client_abort 如果设置为 on, Nginx 在client 停止请求时不会停止向上游服务器请求
proxy_ignore_headers 处理上游服务器返回时设置一组不处理 headers
proxy_intercept_errors 设置开启, Nginx 将显示 error_page 配置的错误而不会向上游服务器请求
proxy_max_temp_file_size The maximum size of the overflow file, written when the response doesn’t fit into memory buffers.
proxy_pass 上游服务器 URL
proxy_pass_header 覆盖被 proxy_hide_header 配置禁用的 headers,允许他们发送给客户端
proxy_pass_request_body off 时阻止向上游服务器发送请求body
proxy_pass_request_headers off 时阻止向上游服务器发送 headers
proxy_read_timeout 连接关闭前,向上游服务器两次读成功耗时
proxy_redirect Rewrites the Location and Refresh headers received from the upstream servers; useful for working around assumptions made by an application framework.
proxy_send_timeout 连接关闭前,向上游服务器两次写成功耗时
proxy_set_body 修改请求body
proxy_set_header 修改请求 headers
proxy_temp_file_write_size 限制单个请求的临时文件大小, Nginx 不会在一个请求上被 block
proxy_temp_path 临时文件地址

upstream 选项中的配置

Directive Explanation
ip_hash 使得客户端的请求能够均匀的分布
keepalive 每一个 worker process 向上游服务器请求缓存的连接数,proxy_http_version 需要设置为 1.1 并且 proxy_set_header 设置为空
least_conn 负载均衡算法,根据 active 连接数来选择下一个连接
server 设置地址,域名或者 IP,或者 Unix-domain socket 一些选项 weight: 设置 server 的权重,max_fails: 重试最大次数,fail_timeout: 服务器超过该时间会被标记为 Down ,backup: 只有其他机器都 Down 情况下才会使用该服务器,down: 标记为 down 不会处理请求

示例

keep alive

以如下配置示例

upstream apache {
	server 127.0.0.1:8080;
	keepalive 32;
}
location / {
	proxy_http_version 1.1;
	proxy_set_header Connection "";
	proxy_pass http://apache;
}

假设定义了 apache upstream ,使用 Nginx 转发到本地 8080 端口, 设置了 keepalive 为 32。每一个 Nginx worker 只会在最初始化时TCP握手建立32个连接,Nginx 会保存连接,不会发送 close

如果需要超过 32 个连接, Nginx 会再新建连接满足需求,如果需求降低, Nginx 会自动将超过 32 个连接的请求,按照最近使用的连接关闭,直到将连接数降到 32 。

负载均衡算法

upstream 模块会使用三种算法来选择向哪一台上游服务器建立连接—- round-robin, IP hash, 或者是 least connections.

round-robin 算法是默认值,算法根据上一次选择的服务器决定下一次选择哪一条连接,算法公平的根据 turn by turn 的方式来保持平衡。

IP hash 算法,需要通过 ip_hash 指令开启 Nginx 使用 IPv4 地址的前三个字节或者是整个 IPv6 地址作为 hashing key 。因此一组IP地址永远被map到特定的上游服务器。因此这个机制不是设计为均匀分发请求,而是被设计成将客户端和上游服务器映射到一起。

第三种负载均衡算法叫做 least connections , 通过 least_conn 开启。该算法设计成将负载均匀的打到上游服务器中,通过选择活跃连接数最小的服务器。如果上游服务器不是具有相同的处理能力,可以通过指定 weight 来人为处理。算法会将不同 weight 的服务器纳入计算活跃连接数的考虑范畴。

创建 Google 的反向代理

创建一个 Ngixn 虚拟主机,我使用 https://g.einverne.info 来演示:

# 配置 google ip 地址,使用 nslookup google.com 来获取 Google 服务器地址,避免 Google 机器人检测
upstream www.google.com {
    server XXX.XXX.XXX.XXX:443 weight=1; #把XXX替换成可用 IP
    server XXX.XXX.XXX.XXX:443 weight=1;
    server XXX.XXX.XXX.XXX:443 weight=1;
    server XXX.XXX.XXX.XXX:443 weight=1;
    server XXX.XXX.XXX.XXX:443 weight=1;
    server XXX.XXX.XXX.XXX:443 weight=1;
    server 216.58.216.163:443 weight=1; #hk
}

server {
    listen 80;
    listen [::]:80;
    server_name g.einverne.info;

    listen 443 ssl;
	ssl_certificate path_to_ssl_crt; # 证书
	ssl_certificate_key path_key; # key

	# 自动 http 转 https
    if ($scheme != "https") {
        return 301 https://$host$request_uri;
    }

    if ($http_user_agent ~* (baiduspider|360spider|haosouspider|googlebot|soso|bing|sogou|yahoo|sohu-search|yodao|YoudaoBot|robozilla|msnbot|MJ12bot|NHN|Twiceler)) {
        return  403;
    }

	# 编译时加入 ngx_http_google_filter_module 模块,location 如下设置
    location / {
        google on;
    }

    access_log /var/log/nginx/g.einverne.info.access.log;
	error_log /var/log/nginx/g.einverne.info.error.log;
}

如果编译时没有加入 ngx_http_google_filter_module 模块,则需要设置 location

location / {
	proxy_redirect off;
	proxy_cookie_domain google.com <domain.name>; 
	proxy_pass https://www.google.com;
	proxy_connect_timeout 60s;
	proxy_read_timeout 5400s;
	proxy_send_timeout 5400s;

	proxy_set_header Host "www.google.com";
	proxy_set_header User-Agent $http_user_agent;
	proxy_set_header Referer https://www.google.com;
	proxy_set_header Accept-Encoding "";
	proxy_set_header X-Real-IP $remote_addr; 
	proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 
	proxy_set_header X-Forwarded-Proto https;
	proxy_set_header Accept-Language "zh-CN";
	proxy_set_header Cookie "PREF=ID=047808f19f6de346:U=0f62f33dd8549d11:FF=2:LD=en-US:NW=1:TM=1325338577:LM=1332142444:GM=1:SG=2:S=rE0SyJh2W1IQ-Maw";

	subs_filter https://www.google.com.hk <domain.name>;
	subs_filter https://www.google.com <domain.name>;
	#subs_filter_types text/css text/xml text/javascript;

	sub_filter_once off; 
}
  • proxy_redirect 设置为 off ,不需要重写 Location 的 header
  • proxy-cookie-domain google <domain.name>; 将cookie作用域替换成自己的域名
  • proxy_pass https://www.google.com; 反向代理到 upstream www.google.com
  • proxy_set_header Accept-Encoding ""; 防止谷歌返回压缩的内容,否则内容无法替换
  • proxy_set_header Cookie 这一行 禁止即时搜索,设置为新窗口打开网站
  • subs_filter https://www.google.com <domain.name>; 把Google域名替换,需要编译时加上 --with-http_sub_module 参数

reference


2017-10-25 linux , nginx , web , proxy , google

Nginx 配置详解

Nginx 的相关介绍及安装可以参考之前的一篇文章

Nginx 相关的配置, Nginx 中的配置有两种分类,一种为单纯的指令 (directive),另一种为上下文配置块 (configuration context)。

指令 (directive),包含名称参数名,以分号结束,比如

gzip on;

上下文通常声明一个作用域,比如 server 块

server {
    listen 80;
}

在上下文中使用相同的指令时需要小心,一般子级上下文中的指令会覆盖父级中定义的值。

全局块

Nginx 的全局配置是影响整个 WEB 服务器的配置。

主要有以下几个

Directive Explanation
user worker process 在配置的 user and group 下运行
workr_processes 最多的 worker processes 数量,可支持并发数,通常的做法是指定和 CPU cores 数量一致
error_log log
pid file where the process ID of the main process is written
use 连接方式
worker_connections 连接数

配置用户用户组

设置用户的配置

user user [group];
  • user, 可运行 Nginx 服务器的用户
  • group, 指定可运行用户组

希望所有用户都可以启动 Nginx 进程,一种是直接注释该配置,或者

user nobody nobody;

Nginx 配置文件中,每一条配置都必须以分号结束。

配置 worker process 数

worker process 是 Nginx 并发关键所在,理论上 worker process 值越大,可支持并发数也越多,但实际也受到软件,操作系统,硬件(CPU 和磁盘)等资源的制约。

worker_processes number | auto;
  • number, 指定 Nginx 进程最多可产生的 worker process 数
  • auto Nginx 自动

PID 存放路劲

Nginx 进程作为系统守护进程运行,在文件中保存当前运行程序主进程号,支持配置 PID

pid file_path;
  • file_path 为存放路劲和文件名

错误日志路劲

全局块、http 块 和 server 块都可以对 Nginx 日志进行配置

error_log file | stderr [debug | info | notice | warn | error |crit | alert | emerg];

Nginx 日志支持输出到文件 file, 或者标准错误输出 stderr.

日志级别可选,从低到高 debug, info, notice, warn, error, crit, alert, emerg ,需要注意的是 debug 需要编译时使用 --with-debug 开启。

引入其他配置

Nginx 提供 include 配置来引入其他文件

include file;
  • file 是要引入的配置文件,支持相对路劲和正则匹配

最大连接数

设置每一个 worker process 同时开启的最大连接数

worker_connections number;

只能在 events 块中配置

定义 MIME TYPE 类型

浏览器使用 MIME Type 来区分不同的媒体类型, Nginx 作为 Web 服务器,必须能够识别前端请求的资源类型。

默认的配置中,可以使用两种方式来配置

include mime.types;
default_type application/octet-stream

第一种方式引用外部文件。

mime.types 文件

types {
	text/html                             html htm shtml;
	text/css                              css;
	text/xml                              xml;
	image/gif                             gif;
	image/jpeg                            jpeg jpg;
	application/javascript                js;
	application/atom+xml                  atom;
	application/rss+xml                   rss;

	text/mathml                           mml;
	text/plain                            txt;
	text/vnd.sun.j2me.app-descriptor      jad;
	text/vnd.wap.wml                      wml;
	text/x-component                      htc;

	image/png                             png;
	image/tiff                            tif tiff;
	image/vnd.wap.wbmp                    wbmp;
	image/x-icon                          ico;
	image/x-jng                           jng;
	image/x-ms-bmp                        bmp;
	image/svg+xml                         svg svgz;
	image/webp                            webp;

	application/font-woff                 woff;
	application/java-archive              jar war ear;
	application/json                      json;
	application/mac-binhex40              hqx;
	application/msword                    doc;
	application/pdf                       pdf;
	application/postscript                ps eps ai;
	application/rtf                       rtf;
	application/vnd.apple.mpegurl         m3u8;
	application/vnd.ms-excel              xls;
	application/vnd.ms-fontobject         eot;
	application/vnd.ms-powerpoint         ppt;
	application/vnd.wap.wmlc              wmlc;
	application/vnd.google-earth.kml+xml  kml;
	application/vnd.google-earth.kmz      kmz;
	application/x-7z-compressed           7z;
	application/x-cocoa                   cco;
	application/x-java-archive-diff       jardiff;
	application/x-java-jnlp-file          jnlp;
	application/x-makeself                run;
	application/x-perl                    pl pm;
	application/x-pilot                   prc pdb;
	application/x-rar-compressed          rar;
	application/x-redhat-package-manager  rpm;
	application/x-sea                     sea;
	application/x-shockwave-flash         swf;
	application/x-stuffit                 sit;
	application/x-tcl                     tcl tk;
	application/x-x509-ca-cert            der pem crt;
	application/x-xpinstall               xpi;
	application/xhtml+xml                 xhtml;
	application/xspf+xml                  xspf;
	application/zip                       zip;

	application/octet-stream              bin exe dll;
	application/octet-stream              deb;
	application/octet-stream              dmg;
	application/octet-stream              iso img;
	application/octet-stream              msi msp msm;

	application/vnd.openxmlformats-officedocument.wordprocessingml.document    docx;
	application/vnd.openxmlformats-officedocument.spreadsheetml.sheet          xlsx;
	application/vnd.openxmlformats-officedocument.presentationml.presentation  pptx;

	audio/midi                            mid midi kar;
	audio/mpeg                            mp3;
	audio/ogg                             ogg;
	audio/x-m4a                           m4a;
	audio/x-realaudio                     ra;

	video/3gpp                            3gpp 3gp;
	video/mp2t                            ts;
	video/mp4                             mp4;
	video/mpeg                            mpeg mpg;
	video/quicktime                       mov;
	video/webm                            webm;
	video/x-flv                           flv;
	video/x-m4v                           m4v;
	video/x-mng                           mng;
	video/x-ms-asf                        asx asf;
	video/x-ms-wmv                        wmv;
	video/x-msvideo                       avi;
}

文件中包含了浏览器能够识别的 MIME 类型,以及对应的文件后缀名。

第二种方式使用 default_type mime-type 直接配置。

Server section

自定义 Access 日志

error_log 不同的是,Nginx 进程运行时访问日志,由 Nginx 提供服务过程中应答前端请求的日志。

Nginx 服务器支持对服务日志的格式、大小、输出等进行配置,需要使用两个配置 access_loglog_format

access_log path [format [buffer=size]];
  • path, 配置服务日志的文件存放路劲及名称
  • format 可选,自定义日志格式,也可以通过 log_format 配置指定好,直接引用格式名
  • size 临时存放日志的内存缓存区大小

如果要取消记录日志功能,使用

access_log off;

自定义日志格式

log_format name string ...;
  • name 格式字符串的名字,默认为 combined
  • string 自定义格式化字符串

示例,配置如下两行

log_format exampleLog '$remote_addr - [$time_local] $request '
					  '$status $body_bytes_sent '
					  '$http_referer $http_user_agent';

access_log /var/log/nginx/access.log exampleLog;

查看日志 tailf /var/log/nginx/access.log

47.88.236.38 - [24/Oct/2017:10:25:30 +0800] GET /post/2017/10/things-to-do-after-install-wordpress.html?ajax_load=page HTTP/1.1 200 6961 https://www.einverne.info/ Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36

可以查看到上面格式的日志,IP 本地时间 请求方法 请求路劲 HTTP 状态 发送数据大小 以及 HTTP refer 和 User Agent.

配置连接超时时间

用户连接回话连接后, Nginx 服务器可以保持打开一段时间

keepalive_timeout timeout [header_timeout];
  • timeout 对连接的保持时间
  • header_timeout 可选,在 Response 头部 Keep-Alive 域设置超时时间

示例

keepalive_timeout 120s 100s;

设置单连接请求数上限

限制用户通过某一个连接向 Nginx 发送请求次数

keepalive_requests number;

虚拟主机配置

虚拟主机配置以 server 开头,server 内的配置都认为是 虚拟主机 配置。虚拟主机定义了一套由不同 server_name 配置区分的资源。虚拟主机一般由 listenserver_name 等一组配置决定。

配置网络监听

监听配置方法主要有三种:

第一种配置监听 IP 地址

listen address[:port] [default_server] [setfib=number] [backlog=number] [rcvbuf=size] [sndbuf=size] [deferred] [accept_filter=filter] [bind] [ssl];

第二种配置监听端口

listen port [default_server] [setfib=number] [backlog=number] [rcvbuf=size] [sndbuf=size] [accept_filter=filter] [deferred] [bind] [ipv6only=on|off] [ssl];

第三种配置 UNIX Domain Socket

listen unix:path [default_server] [backlog=number] [rcvbuf=size] [sndbuf=size] [accept_filter=filter] [deferred] [bind] [ssl];
  • 使用 default_server 将虚拟主机地址设置为 address:port 为默认
  • setfib 不常用
  • backlog 设置监听函数 listen() 最多运行多少网络连接同时处于挂起状态
  • rcvbuf 监听 socket 接受缓存区大小
  • sndbuf 监听 socket 发送缓存区大小
  • ssl 回话使用 SSL 模式

配置虚拟主机名称

主机是指 server 块对外提供虚拟主机

server_name name ...;

名字就是域名,用空格隔开

server_name einverne.info www.einverne.info;

Nginx 规定第一个名称作为虚拟主机的主要名

name 中可以使用通配符 * ,但通配符只能放到首尾,name 中还能使用正则表达式,使用 ~ 开始

server_name ~^ww\d+\.einverne\.info$;

匹配 ww1.einverne.info 但不匹配 www.einverne.info

对于不同的匹配方式,Nginx 按照如下优先级选择虚拟主机

  • 准确匹配 server_name
  • 通配符在开始时匹配 server_name 成功
  • 通配符在结尾时匹配 server_name 成功
  • 正则表达式匹配

在以上四种匹配方式中,如果 server_name 被处于同一优先级匹配方式匹配多次成功,则首次匹配成功的虚拟主机处理请求。

基于 IP 的虚拟主机配置

不是很常用,暂时略

配置 location 块

location 指令在 virtual server 部分使用,用来比欧式 URI 怎么处理。

语法

location [ = | ~ | ~* | ^~ ] uri { ... }

其中,uri 变量是待匹配的请求字符串,可以是不含正则表达的字符串。

方括号中为可选项,不添加可选项时, Nginx 首先在 server 块多个 location 块中搜索是否有匹配,如果有多个匹配,就记录匹配度最高的一个。然后,Nginx 再用 location 块中的正则 uri 和请求匹配,当第一个正则匹配成功,结束搜索,并使用该 location 块处理请求,如果正则全部失败,则使用刚才记录的匹配度最高的 location 块处理该请求。

了解了 location 块匹配规则,再来看一下各个可选项的含义:

  • = 用于非正则 uri 前,要求字符串与 uri 严格匹配,如果匹配成功,则停止向下搜索,并立即处理此请求
  • ~ 表示该 uri 包含正则,并且区分大小写
  • ~* 表示 uri 包含正则,不区分大小写
  • ^~ 用于非正则 uri 前,Nginx 服务器找到标示 uri 和请求字符串匹配程度最高的 location 后立即使用该 location 处理请求,不再匹配 location 块的正则 url

如果 uri 包含正则,则必须使用 ~~* 。 而对于 ^~ 会对 uri 中的 urlencode 内容解码, %20 会被理解为空格。

配置请求的根目录

Nginx 接受到请求之后,在服务器指定目录中寻求资源

root path;

path 为 Nginx 接受到请求之后查找资源的根目录路劲。 path 变量可以包含 Nginx 服务器预设的大多数变量,但要注意 $document_root$realpath_root 不可用。

该配置可以再 http 块、 server 块或者 location 块中进行配置。

更改 location 的 URI

在 location 块中,除了使用 root 命令指明请求处理根目录,还可以使用 alias 配置来改变 location 接收到的 URI 请求

alias path;

path 就是修改后的根路劲。

示例

location ~ ^/data/(.+\.(htm|html)) $ {
	alias /var/www/data/$1;
}

当 location 块接收到 /data/index.html 请求时,匹配成功,根据 alias 配置, Nginx 在 /var/www/data/ 目录下找到 index.html 并响应请求。

关于 root 和 alias 的区别 可以参考这篇文章

设置网站默认首页

在用户发出请求时,请求地址可以不填写首页完整路劲

index file ...;

设置错误页面

指定错误页面

error_page code ... [=[response]] uri
  • code 要处理的 HTTP 错误代码
  • response 可选项,将 code 指定的错误转化为新的错误代码 response
  • uri 错误页面的路劲或者网站地址

示例

error_page 404 /404.html

基于 IP 配置 Nginx 访问权限

Nginx 支持两种途径的基本访问控制,一种是由 HTTP 标准模块的 ngx_http_access-modele 支持,通过 IP 来判断客户端是否拥有对 Nginx 的访问权限

allow 配置用于设置 Nginx 客户端 IP 访问

allow address | CIDR | all;
  • address 允许访问的客户端 IP,不支持同时设置多个
  • CIDR 允许访问的客户端 CIDR 地址, 202.112.18.23/25,前 32 位 IP 地址,后面 ”/25“ 表示前 25 位是网络,其余代表主机部分
  • all 代表允许所有客户端访问

deny 配置,顾名思义

deny address | CIDR | all;

参数含义同上

Nginx 对于访问控制权限是顺序匹配,如果匹配成功就不会继续向下解析。

配置密码设置 Nginx 访问权限

Nginx 支持 HTTP Basic Authentication 协议的认证,该协议是一种 HTTP 性质的认证办法,需要用户名和密码,认证失败的客户端不拥有访问 Nginx 服务器的权限。

开启或者关闭

auth_basic string | off;
  • string 开启该认证功能,并验证配置时显示的提示信息
  • off 关闭该功能

    auth_basic_user_file file;

其中 file 为密码文件的绝对路劲

使用如下命令创建用户名密码到文件

printf "yourusername:$(openssl passwd -apr1)" > /etc/nginx/passwords

记住替换 yourusername ,该命令会在 /etc/nginx 目录下创建 passwords 文件,该文件的格式为

yourusername:passwordencrypt

也可以使用 htpasswd 命令来生成,绝大部分语言提供 crypt() 函数来对加密密码

htpasswd -c -d /etc/nginx/passwords yourusername

然后添加如下配置

server {
	# ...
	auth_basic "Protected";
	auth_basic_user_file passwords;
	# ...
}

反向代理配置

简单配置

server
{
	listen          80;
	server_name     g.einverne.info;
	location / {
		proxy_pass          http://www.google.com/;  #反代的域名
		proxy_redirect      off;
		proxy_set_header    X-Real-IP       $remote_addr;
		proxy_set_header    X-Forwarded-For $proxy_add_x_forwarded_for;
	}
}

reference

  • Nginx 高性能 Web 服务器详解

2017-10-23 nginx , web , server , linux , proxy

GitHub 使用 gpg 签名

Ubuntu 下,GnuPG 2.0 的支持都在 gnupg2 这个 packages 下,通过下面命令安装:

sudo apt-get install gnupg2

GitHub 要求使用 GnuPG 2.1 及以后的版本。

生成 GPG 签名

使用

gpg2 --full-gen-key
  1. 选择默认 RSA and RSA
  2. 推荐 4096
  3. 过期时间
  4. 相关信息包括 Real name, Email, Comment(comment 可以写一些标示)
  5. 密码

如果遇到尝试卡在生成签名的步骤,提示

We need to generate a lot of random bytes. It is a good idea to perform
some other action (type on the keyboard, move the mouse, utilize the
disks) during the prime generation; this gives the random number
generator a better chance to gain enough entropy.

可能需要安装 rng-tools

sudo apt install rng-tools

之后在执行上面的命令。

使用以下命令查看本地密钥

gpg2 --list-keys --keyid-format LONG

结果

/home/einverne/.gnupg/pubring.gpg
---------------------------
sec   rsa4096/F80B65AAAAAAAAAA 2018-01-31 [SC]
uid                 [ultimate] Ein Verne (co) <email@address>
ssb   rsa4096/B63A4CAAAAAAAAAA 2018-01-31 [E]

将其中的第三行 sec 中 rsa4096 以后的 ID 记住,拷贝出来。

然后使用

gpg2 --armor --export ID

来获取 GPG KEY,拷贝 -----BEGIN PGP PUBLIC KEY BLOCK----------END PGP PUBLIC KEY BLOCK----- 之前,包括这两行的内容到 GitHub。

配置 GPG

产生 GPG,并且已经添加到 GitHub 后台,那么需要本地配置,告诉 git 本地签名。查看本地 gpg

gpg2 --list-keys --keyid-format LONG

添加配置,这里记得使用公钥

git config --global user.signingkey F80B65AAAAAAAAAA
git config --global gpg.program gpg2

将 GPG 添加到 bashrc

echo 'export GPG_TTY=$(tty)' >> ~/.bashrc

签名 commit

在提交时使用 -S 选项

git commit -S -m your commit message

来本地签名提交

提交标签同理

git tag -s mytag

可以使用 -v 来验证

git tag -v mytag

其他 gpg 命令

列出公钥

gpg2 --list-keys

查看秘钥

gpg2 --list-secret-keys

删除 uid 私钥

gpg2 --delete-secret-keys [uid]

删除 uid 公钥

gpg2 --delete-keys [uid]

reference


2017-10-20 github , git , gpg , linux

升级 Spring MVC 3.2.x 到 4.x 注意事项

把 Spring 版本从 3.2.x 升级到了4.x ,这里记录一下。

新特性

Java 8 Support, 从 4.0 开始支持 Java 8,可以使用 lambda 表达式,等等 Java 8 的特性

Groovy DSL

新增 @RestController 注解,这样就不需要每个方法都使用 @ResponseBody 了。

更多内容可以查看: https://docs.spring.io/spring/docs/4.3.x/spring-framework-reference/htmlsingle/#spring-whats-new

注意事项

添加依赖

加入spring-context-support,以前3的版本不用加,但是4要加上,否则就会报ClassNotFoundException,

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context-support</artifactId>
    <version>4.3.12.RELEASE</version>
</dependency>

替换 Spring MVC jackson 依赖

更换Spring jackson依赖,Spring MVC返回 json 的时候需要依赖jackson的jar包,以前是codehaus.jackson,现在换成了fasterxml.jackson 同时修改配置文件

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-core</artifactId>
    <version>2.7.0</version>
</dependency>

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.7.0</version>
</dependency>

同时还要修改Spring的配置文件

<bean
    class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
    <property name="messageConverters">
        <list>
             <ref bean="stringHttpMessageConverter" />  
            <bean
                class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
            </bean>
        </list>
    </property>
</bean>

<bean id="stringHttpMessageConverter"
    class="org.springframework.http.converter.StringHttpMessageConverter">
    <property name="supportedMediaTypes">
        <list>
            <value>text/plain;charset=UTF-8</value>
        </list>
    </property>
</bean>

xsd 文件版本

更换springxsd文件的版本,直接从 3.0 升级到 4.0 即可

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">

修改 quarz 版本

修改quarz版本,用2以上的版本,maven依赖如下

<dependency>
    <groupId>org.quartz-scheduler</groupId>
    <artifactId>quartz</artifactId>
    <version>2.2.2</version>
</dependency>

2017-10-19 Spring , Java , Web

Linux 安装 nodejs

nodejs 安装其实非常简单,大部分情况下 Debian/Ubuntu 下只要使用包管理直接安装

sudo apt-get install nodejs
sudo apt-get install npm

即可。

脚本安装

可是今天网络环境太差,不是 npm package not found 就是 update 半天不动。

官网 提供的安装方式

curl -sL https://deb.nodesource.com/setup_8.x | sudo -E bash -
sudo apt-get install -y nodejs

也是网络环境无法安装

二进制安装

所以使用 二进制 安装

在官网 https://nodejs.org/en/download/ 找到编译好的二进制文件

然后解压到 /usr/local 目录下

然后配置 vim ~/.zshrc

export NODE_HOME=/usr/local/node-v6.11.4-linux-x64/
export PATH=$NODE_HOME/bin:$PATH

使用命令检查

node -v
npm -v

输出即可。


2017-10-18 linux , nodejs , npm , js , javascript

使用 mutt 在 Bash 中发送邮件及附件

在编写定时备份脚本时遇到一个需求,就是在 Bash 脚本中发送带附件的邮件。于是找到了 mutt。

Mutt 是一个命令行的邮件客户端,Mutt 能够轻松地在命令行发送和读取邮件。 Mutt 支持 POP 和 IMAP 协议。 尽管 Mutt 是基于命令的,但也同样有一个友好的界面。

如果不使用界面,使用 Mutt 命令发邮件也非常方便,只需要一条命令即可发送或者批量发送邮件。

功能说明

E-mail 管理程序。

语法

mutt [-hnpRvxz][-a 文件][-b 地址][-c 地址][-f 邮件文件][-F 配置文件][-H 邮件草稿][-i 文件][-m 类型][-s 主题] 邮件地址

补充说明:mutt 是一个文字模式的邮件管理程序,提供了全屏幕的操作界面。

参数:

  • -a 文件 在邮件中加上附加文件。
  • -b 地址 指定密件副本的收信人地址。
  • -c 地址 指定副本的收信人地址。
  • -f 邮件文件 指定要载入的邮件文件。
  • -F 配置文件 指定 mutt 程序的设置文件,而不读取预设的.muttrc 文件。
  • -h 显示帮助。
  • -H 邮件草稿 将指定的邮件草稿送出。
  • -i 文件 将指定文件插入邮件内文中。
  • -m 类型 指定预设的邮件信箱类型。
  • -n 不要去读取程序培植文件 (/etc/Muttrc)。
  • -p 在 mutt 中编辑完邮件后,而不想将邮件立即送出,可将该邮件暂缓寄出。
  • -R 以只读的方式开启邮件文件。
  • -s 主题 指定邮件的主题。
  • -v 显示 mutt 的版本信息以及当初编译此文件时所给予的参数。
  • -x 模拟 mailx 的编辑方式。
  • -z 与 -f 参数一并使用时,若邮件文件中没有邮件即不启动 mutt。

安装方法

Debian/Ubuntu/Linux Mint 安装

sudo apt-get install -y mutt

使用方法

发送一封简单的邮件(可能会被主流邮箱认为垃圾邮件,垃圾箱查看一下)

echo "Email body" | mutt -s "Email Title" root@einverne.info

进入命令行交互界面之后使用如下快捷键操作

  • 使用 t 改变接受者邮件地址
  • 使用 c 改变 Cc 地址
  • 使用 a 来增加附件
  • 使用 q 退出
  • 使用 y 来发送邮件

发送带附件的邮件

echo "body" | mutt -s "mysql backup" root@einverne.info -a /mysql.tar.gz

读取文本中的信息作为内容

mutt -s "Test" xxxx@qq.com

添加多个附件

echo "body" | mutt -s "web backup" root@einverne.info -a /mysql.tar.gz -a /web.tar.gz

抄送和密送

echo "body" | mutt -s "title" -c cc@gmail.com -b bcc@gmail.com root@einverne.info
  • 使用 -c 来抄送
  • 使用 -b 来添加密送
  • 使用 -s 来添加标题
  • 使用 -a 来添加附件

设置发件人

编辑配置文件

vi /etc/Muttrc

添加如下内容,防止被作为垃圾邮件

set from="mutt@einverne.info"
set use_from=yes
set envelope_from="yes"
set realname="Ein Verne"

mutt@einverne.info 为发信地址

mutt 发送邮件略慢,需要等待一分钟或者更长才能发送成功,作为备份工具好好利用。

reference


2017-10-17 linux , email , mutt

在 Spring Boot 中使用 Swagger

在使用 Spring Boot 构建一套 RESTful 接口的时候经常需要手工维护一份接口文档以提供给不同的客户端使用,有的时候手工维护成本太高,今天发现了一套自动化生成 RESTful 接口文档的工具 Swagger 。

Swagger 能根据 Spring Controller 接口自动生成一个文档页面,在代码中使用注解将接口文档注释,非常方便。 Swagger 整合到 Spring boot 项目中也非常方便。

添加依赖

pom.xml 中添加

<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger2</artifactId>
    <version>2.7.0</version>
</dependency>
<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger-ui</artifactId>
    <version>2.7.0</version>
</dependency>

最新的版本可以在 mvnrepository 上查到,或者上官网或者 github。

添加配置类

在项目 package 根下新建如下 Class:

@Configuration
@EnableSwagger2
public class SwaggerConfig {

    @Bean
    public Docket helloApi() {
        return new Docket(DocumentationType.SWAGGER_2)
                .apiInfo(apiInfo())
                .select()
                .apis(RequestHandlerSelectors.basePackage("info.einverne.springboot.demo"))
                .paths(PathSelectors.any())
                .build();
    }

    private ApiInfo apiInfo() {
        return new ApiInfoBuilder()
                // 文档标题
                .title("API 文档")
                // 文档描述
                .description("https://github.com/einverne/thrift-swift-demo/tree/master/spring-boot-demo")
                .termsOfServiceUrl("https://github.com/einverne/thrift-swift-demo/tree/master/spring-boot-demo")
                .version("v1")
                .build();
    }
}

通过@Configuration注解,让 Spring 来加载该类配置。再通过@EnableSwagger2注解来启用 Swagger2。

  • apiInfo() 用来创建 API 的基本信息,展现在文档页面中。
  • select() 函数返回一个 ApiSelectorBuilder 实例用来控制哪些接口暴露给 Swagger ,这里使用定义扫描包路径来定义, Swagger 会扫描包下所有 Controller 的定义并产生文档内容,除了被 @ApiIgnore 注解的接口。

添加接口注释

@ApiOperation 注解来给 API 增加说明、通过 @ApiImplicitParams、@ApiImplicitParam 注解来给参数增加说明。

一个简单的注释

@ApiOperation(value = "创建用户", notes = "根据 User 对象创建用户")
@ApiImplicitParam(name = "user", value = "用户详细实体 user", required = true, dataType = "User")
@RequestMapping(value = "", method = RequestMethod.POST)
public String postUser(@RequestBody User user) {
    users.put(user.getId(), user);
    return "success";
}

详细的例子可以参考源代码 https://github.com/einverne/thrift-swift-demo

再添加注释后启动 Spring boot, 访问 http://localhost:8080/swagger-ui.html 即可看到 API 文档

Api 注解

@Api 注解用于类上,说明类作用

  • value url
  • description
  • tags 设置该值,value 会被覆盖
  • basePath 基本路劲不可配置
  • position
  • produces “application/json”
  • consumes “application/json”
  • protocols http, https, wss
  • authorizations 认证
  • hidden 是否在文档隐藏

ApiOperation 注解

标记在方法上,对一个操作或 HTTP 方法进行描述。具有相同路径的不同操作会被归组为同一个操作对象。不同的 HTTP 请求方法及路径组合构成一个唯一操作。此注解的属性有:

  • value 对操作的简单说明,长度为 120 个字母,60 个汉字。
  • notes 对操作的详细说明。
  • httpMethod HTTP 请求的动作名,可选值有:”GET”, “HEAD”, “POST”, “PUT”, “DELETE”, “OPTIONS” and “PATCH”。
  • code 默认为 200,有效值必须符合标准的 HTTP Status Code Definitions

ApiImplicitParams

注解 ApiImplicitParam 的容器类,以数组方式存储。

ApiImplicitParam

对 API 的单一参数进行注解。虽然注解 @ApiParam 同 JAX-RS 参数相绑定,但这个 @ApiImplicitParam 注解可以以统一的方式定义参数列表,也是在 Servelet 及非 JAX-RS 环境下,唯一的方式参数定义方式。注意这个注解 @ApiImplicitParam 必须被包含在注解 @ApiImplicitParams 之内。可以设置以下重要参数属性:

  • name 参数名称
  • value 参数的简短描述
  • required 是否为必传参数
  • dataType 参数类型,可以为类名,也可以为基本类型(String,int、boolean 等)
  • paramType 参数的传入(请求)类型,可选的值有 path, query, body, header or form。

@RequestBody 这样的场景请求参数无法使用 @ApiImplicitParam 注解进行描述

ApiParam

增加对参数的元信息说明。这个注解只能被使用在 JAX-RS 1.x/2.x 的综合环境下。其主要的属性有:

  • required 是否为必传参数
  • value 参数简短说明

ApiModel

提供对 Swagger model 额外信息的描述。在标注 @ApiOperation 注解的操作内,所有的类将自动被内省(introspected),但利用这个注解可以做一些更加详细的 model 结构说明。主要属性有:

  • value model 的别名,默认为类名
  • description model 的详细描述

ApiModelProperty

对 model 属性的注解,主要的属性值有:

  • value 属性简短描述
  • example 属性的示例值
  • required 是否为必须值
  • hidden 隐藏该属性

ApiResponse

响应配置

  • code http 状态码
  • message 描述

ApiResponses

多个 Response

验证机制

考虑到安全的问题,每次请求 API 需要对用户进行验证与授权。目前主流的验证方式采用请求头部(request header)传递 token,即用户登录之后获取一个 token,然后每次都使用这个 token 去请求 API。如果想利用 swagger-UI 进行 API 测试,必须显式为每个需要验证的 API 指定 token 参数。这时可以为每个操作添加一个注解 @ApiImplicitParams,具体代码如下:

@ApiImplicitParams({@ApiImplicitParam(name = "TOKEN", value = "Authorization token", required = true, dataType = "string", paramType = "header")})

根据环境选择开启 Swagger

Swagger 提供了 enable 方法,可以通过设置该方法来选择开启 Swagger 来在线上环境禁用 Swagger。

@Bean
public Docket customImplementation(){
    return new Docket(SWAGGER_2)
        .apiInfo(apiInfo())
        .enable(environmentSpeficicBooleanFlag) //<--- Flag to enable or disable possibly loaded using a property file
        .includePatterns(".*pet.*");
}

如果使用 Spring @Profile 也可以

@Bean
@Profile("production")
public Docket customImplementation(){
    return new Docket(SWAGGER_2)
        .apiInfo(apiInfo())
        .enable(false) //<--- Flag set to false in the production profile
        .includePatterns(".*pet.*");
}

From: https://stackoverflow.com/a/27976261/1820217

reference


2017-10-16 Spring , Swagger , Java

电子书

最近文章

  • MySQL 中的日志配置和管理 MySQL 中默认是没有开启日志记录的,所以需要手动修改配置文件开启日志。而在 MySQL 中我们需要关心的有三类日志:
  • Java 查漏补缺之:ThreadLocal 使用 ThreadLocal 线程本地变量,每个线程保存变量的副本,对副本的改动,对其他的线程而言是透明的。
  • 为知笔记导出和备份 WizNote 已经用了好几年,虽然也一直在续费,但总感觉将死不死,基于整理这几年近 4000 条的笔记的目的,也一方面为迁移出 WizNote 的目的,研究一下 WizNote 笔记导出和备份的方法。
  • Nginx location 匹配规则 之前的关于 Nginx Config 的文章是当时看 Nginx 书记录下来的笔记,很大略,没有实际操作,等终究用到 location 的时候发现还是有很多需要注意的问题,比如匹配的优先顺序,比如 root 和 alias 的区别等等,所以单独拿一篇文章来记录一下目前遇到的问题,并来解决一下。
  • koajs 简单使用 Koa 是一个背靠 Express 的团队设计的全新的 Web 框架,旨在使之成为一个更轻量,更丰富,更加 robust 的基础框架。通过促进异步方法的使用,Koa 允许使用者抛弃 callback 调用,并且大大简化了错误处理。Koa 并没有将中间件绑定到核心代码,而是提供了一组优雅的方法让编写服务更加快速,通过很多第三方的扩展给 Koa 提供服务,从而实现更加丰富完整的 HTTP server。