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

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

安装

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

Git commit 中使用 gpg 签名提交

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

sudo apt-get install gnupg2

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

Mac 下安装使用

在 Mac 下需要安装:

brew install gnupg
brew link --overwrite gnupg
brew install pinentry-mac # 密码输入管理器

然后在 shell 配置 (.bashrc~/.zshrc) 中添加 export GPG_TTY=$(tty).

添加配置

echo "pinentry-program /usr/local/bin/pinentry-mac" >> ~/.gnupg/gpg-agent.conf
killall gpg-agent

然后可以通过 echo "test" | gpg --clearsign 来验证一下。

Mac 下应该会弹出 GUI 窗口进行密码验证。

然后不要忘记配置 git config:

git config --global gpg.program gpg        # 配置全局的 gpg
git config --global commit.gpgsign true    # 配置每一个 commit 都需要 gpg

这里需要注意的一点是 Mac 下命令还叫做 gpg,但是在 Linux 下是 gpg2.

生成 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
---------------------------
pub   rsa4096/F80B65AAAAAAAAAA 2018-01-31 [SC]
uid                 [ultimate] Ein Verne (co) <email@address>
sub   rsa4096/B63A4CAAAAAAAAAA 2018-01-31 [E]

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

然后使用

gpg2 --armor --export ID | xclip -sel c

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

使用 | xclip -sel c 可以直接将命令输出结果拷贝到系统粘贴板。

配置 GPG

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

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

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

# 设置 gitconfig 配置签名的公钥 key
git config --global user.signingkey F80B65AAAAAAAAAA
# 设置签名使用的 gpg 软件
git config --global gpg.program gpg2
# 默认全部签名
git config --global commit.gpgsign true

将 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 命令

生成 gpg key

gpg2 --full-generate-key

列出本地所有公钥

gpg2 --list-keys

查看秘钥

gpg2 --list-secret-keys

删除 uid 私钥

gpg2 --delete-secret-keys [uid]

删除 uid 公钥

gpg2 --delete-keys [uid]

问题

使用过程中遇到的一些问题

提交 commit 时 failed to sign the data

git commit -S 时如果遇到:

gpg: signing failed: Operation cancelled
gpg: signing failed: Operation cancelled
error: gpg failed to sign the data
fatal: failed to write commit object

尝试

export GPG_TTY=$(tty)

强制每次 git 提交使用 gpg 加密

git config --global commit.gpgsign true

对应如果选择关闭就直接使用 false 即可。

导出私钥用于不同电脑之间同步

在一台电脑中生成的 gpg secret key 可以用于不同的电脑

  • 首先运行 gpg2 --list-secret-keys 来确认本机的私钥,需要记住私钥的 ID (在第二列)
  • 导出私钥 gpg2 --export-secret-keys $ID > my-private-key.asc
  • 拷贝私钥到目标机器 (scp)
  • 导入私钥 gpg2 --import my-private-key.asc

如果在第二台机器中已经有了公钥,私钥,那么需要分别删除 gpg2 --delete-keysgpg2 --delete-secret-keys

如果熟悉 scp 可以直接将 ~/.gnupg 目录复制到新机器中:

scp -rp ~/.gnupg name@server_ip:~/

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

输出即可。

reference


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

Podcast 频道推荐

Podcast 作为一种特殊的借助声音传播的媒体,有着特定的适用场景和范围。对于我来说每当我需要放空我自己,而又需要使用眼睛和手的时候,比如长时间走路,开车,再比如乘坐地铁等等情况下都会不自觉的打开一集播客。对于固定时间的上下班时间会听固定时长差不多在 1h 左右的内容,而其他时刻根据不同的时长可能会有短到 10 分钟,或者长 30 分钟的内容。

拿播客跟传统电台广播相比,播客的制作可能会更加精良,主题更加集中,信息密度更大一些,大部分往往是针对某一个话题进行介绍或者讨论。

推荐使用通用性客户端订阅收听,比如 Google Podcasts,或者 Pocket Casts 等等,后文有整理。

每期必听

反派影评

反派影评:个人看电影比较多,从偶然听到一期“观影风向标”开始就一直追随者波米到了“反派影评”,这些年陆陆续续也听过不少影评类节目,但只有反派让我一直坚持到现在仍然每期必听。如果你是一个观影爱好者,那就一定不能错过这一档节目。反派影评在 Podcast 上只更新长节目,短节目还是要上微信公众号的。

  • 主题内容:每期主题一部电影,根据这部电影展开,从导演到演员等等
  • 时长:1h 以上
  • 更新周期:每周,但时间不固定

Self-Hosted

Self-Hosted 是一个关于如何自建各种服务,将自己的数字生活以及产生的数据自我管理的播客。

Talk Python to me (by Michael Kennedy)

这是一个和 Python 相关的播客,但是又不止于 Python,还包括 Data Science,AI,Web development 等等话题。

  • 官网:https://talkpython.fm/
  • 主题内容:Python 相关
  • 时长: 1h 左右
  • 更新周期:大致为一周

This American Life

DescriptionThis American Life is an American weekly hour-long radio program produced in collaboration with Chicago Public Media and hosted by Ira Glass. It is broadcast on numerous public radio stations in the United States and internationally, and is also available as a free weekly podcast.

  • 主题内容:This American Life
  • 时长: over 1 hour
  • 更新周期:大致为一周

Talk to me in Korean

学习基础韩国语的节目

  • 主题内容:韩语基础会话
  • 时长: less than 10min
  • 更新周期:大致为一周

牛津人文通识解读

从传统意义上这应该算是讲座了,因为《通往奴役之路》而在 YouTube 上得知这一个主题的演讲,所以下载之后转成音频在路上听了。演讲者是西北政法大学的副教授谌洪果,因为一些缘故辞职了。所以我们才能在 YouTube 上看到这一个系列的讲座,主讲的材料是基于《牛津人文通识》这样一套书籍,这一系列的书大多都是哲学类,或者哲学家相关的书籍,当然也有比如现代日本,美国大法官之类。这一个系列的讲座每一期围绕一本书进行一段分享,YouTube 上的内容不全,不过也陆陆续续听了 24 期,可以说每一期都非常值得听,现在依然记忆深刻的有,哈耶克的,美国最高法院,现代日本等等话题。

  • 主题内容:围绕牛津人文通识读本每期分享一期
  • 时长:1h-2h
  • 更新周期:不固定

Acquired

Acquired 是一个关注科技圈成功的收购和上市的节目,两位主持人 David 和 Ben 在投资界都有一定的经验 1, 能够听出来每一期节目都有非常充足的材料。有的时候他们也会分析一些国内的成功投资经验,比如 Tencent,Xiaomi,Alibaba 等等,也有一些非常热门的话题比如 Tesla,GitHub etc。

  • 官网:https://www.acquired.fm/
  • 主题内容:Exploring, Analyzing, and Grading Technology Acquisitions and IPOs
  • 时长:2h 左右
  • 更新周期:Season 季播,更新时周更

内核恐慌

听“两个中老年人程序员” 聊天。

  • 主题内容:程序,Mac,设计,字体,软件包等等
  • 时长:100 分钟以上
  • 更新周期:节目更新时间不固定

疯投圈

内核恐慌主持人 Rio 的另一档节目,年初刚开始听,果然质量还是不错的

  • 主题内容:投资,科技,消费,各行各业
  • 时长:60 分钟以上
  • 更新周期:节目更新时间不固定,一般月更

故事 FM

听不同人讲自己的故事。

  • 主题内容:不定
  • 时长:小于 30 min
  • 更新周期:每 3 天左右

日本自由行

青岛刘伟品质旅游主播的一档节目,主播是一位从事多年日本旅游工作的导游,从日本文化,历史,饮食,等等方面对日本做出一些介绍。当时就是随心所听,节目不长,声音录制设备也不是很好,但是内容短小精湛非常不错,在主播的推荐下陆陆续续接触了日本文化,甚至看了《日本论》《静观日本》等等书籍。

主播本人是一位职业导游,从 90 十年代开始从事中日导游,翻译工作,给国人定制深度旅游,也接待日方游客。节目内容重在文化,历史,从历史文化中了解日本人的礼仪,美学等等方面。

  • 主题内容:日本文化,旅游,自由行
  • 时长:30 分钟左右
  • 更新周期:前期节目不固定,后面固定为每周三更新

非每期必听但值得一提

忽左忽右

主题不固定,主要在于媒体,投资,互联网等等

  • 主题内容:不固定
  • 时长:30 分钟到 1 小时不定
  • 更新周期:不固定

静说日本 徐静波

或许直接去看讲述日本的书,要比直接听这个要好很多。个人不是非常喜欢这个频道。

  • 主题内容:日本
  • 时长:20 分钟以下
  • 更新周期:大概每周

百靈果 NEWS

这是一档台湾人做的双语国际新闻平台,当然听到后期就会发现主播们打着双语的旗号,其实更多的是在“聊天”,或者用他们自己的话说,就是“讲干话”。当然继续收听他们的节目主要是主播二人非常有趣。

国际新闻,双语,读书,闲聊,台湾

  • 主题内容:不固定
  • 时长:30 分钟到 1 小时不定
  • 更新周期:不固定

陌声人

每一期会分享一本图书

一席

朋友推荐,听了多抓鱼创始人的一集,确实不错,可以选择自己喜欢的话题和主题来听。通常情况下一集大概半个小时左右,会邀请以为专业人士就某一个话题进行演讲,看成是国内复刻版的 TED 吧。

  • 主题内容:
  • 时长:
  • 更新周期:

Breaking into Board Games

看名字就知道是和桌游相关的内容了

  • 主题内容:
  • 时长:
  • 更新周期:

翻转电台

一档和哲学,政治,经济,平民文化相关的电台

  • 主题内容:哲学、政治、经济、平民文化
  • 时长:30min~1h 不等
  • 更新周期:每周

InSession Film Podcast

一档英语影评节目

  • 主题内容:电影,演员,导演
  • 时长:1h 以上不等
  • 更新周期:Every 2 or 3 days.

政见合集

时政

选 美

美国政治

欧罗万象

NPR Up first

综合新闻

The Daily

纽约时报的 The Daily 专题报道

The Dropout

ABC The Dropout 听深度报道

欧洲政局变化

Planet Money

这档节目来自 NPR,绝对的明星节目。每期不到 30 分钟,把抽象的经济理论和政治决议与日常生活的种种现象结合,或者通过一个普通的生活事例分析出里面蕴含的经济学道理。听这档节目会上瘾。

曾经听过但个人不是很推荐

每个人都个人的喜好,网上很多 list 也不都是我最喜欢的博客,我觉得能够找到方法找到自己喜欢的某一类播客就是很好的,授人以鱼不如授人以渔,就是这样,但是这些我听过,并不是非常喜欢的播客我也列出来,喜不喜欢可以自行判断。

  • 代码时间
  • 电影不无聊
  • 闲侃日本
  • 新闻酸菜馆

Podcast 客户端推荐

早之前在 Android 的时候买过 Pocket Cast 可是竟然发现这家每个平台都要收费,不管是 Web ,还是 Android/iOS 客户端,每一个都是单独收费,尽管能够同步订阅列表,但后来转用 iOS 也就放弃了这个客户端,我用过的几个还不错的

  • Podcasts 苹果自身的客户端,虽然设计和使用都不是那么美观和人性化,但只要订阅了就会默默在 wifi 下帮你下载好,不用每一次上路了才想起来
  • Castbox,一款新出的客户端,客户端全免费,甚至网页版还提供博客平台的托管,虽然国内使用速度略慢,但是是我用过的里面体验比较好的了

至于其他人推荐的 Castro, Overcast 如果不缺钱的话买就行了。个人觉得重要的是内容,还有同步的功能,我希望我订阅的内容跟着账号走,而不是跟着设备走。其他国内的 app 比如 喜马拉雅,蜻蜓,荔枝 FM, 听伴 就凭着个人喜好选择即可。

至于为什么不推荐国内的这些 FM,是因为本来 Podcast 是一个公开分享的渠道,发布到 Podcast 上的内容可以被全世界的人访问到,而国内的 FM 都是闭门造车,封闭自己的用户,限制用户只能在他们的平台上传,听众也只有他们平台的账号才能收听,所有的内容就像是自家花园,外人不得入内。而放到 iTunes 的 Podcast 就像是放到了博物馆,全世界的人只要觉得有用就都能够收听到。而且封闭的环境导致审查异常严格,甚至聊电影都能碰到审查,同样也就导致了低智化内容泛滥,内容越没有思考越能得到平台的推荐,自此循环往复,推荐榜单就几乎没有能听的内容了。而在 Podcast 中反而一些很小众的 Channel 内容质量异常高,在某一个专业领域分享的知识,内容足够填满整个频道。

Podcast Hosting

其他站点

一个关于博客统计信息的站点

  • https://chartable.com/
  • https://github.com/guipdutra/awesome-geek-podcasts#in-chinese
  • https://wanqu.co/b/57/2017-03-03-podcasts.html

reference


2017-10-17 podcast , audio , castbox , pocket-cast , google-podcasts

在 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

每天学习一个命令: Linux 查看磁盘信息命令 di

平时在 Linux 上查看磁盘信息都使用 df -lh , -l 显示本地文件系统, -h 来表示 human readable 。虽然 df 在一定程度上能够满足查询磁盘剩余空间的需求,但是这里要介绍一款强大于 df 的命令 —- di 。

使用如下命令安装

sudo apt install di

di 命令是 disk information 的缩写,直接运行 di 会有如下结果

di
Filesystem         Mount               Size     Used    Avail %Used  fs Type
/dev/sda1          /                 901.2G   188.3G   667.1G   26%  ext4   
tmpfs              /dev/shm            7.8G     0.1G     7.6G    2%  tmpfs  
tmpfs              /run                1.6G     0.1G     1.5G    4%  tmpfs  
cgmfs              /run/cgmanager/     0.1M     0.0M     0.1M    0%  tmpfs  
tmpfs              /run/lock           5.0M     0.0M     5.0M    0%  tmpfs  
tmpfs              /run/user/0         1.6G     0.0G     1.6G    0%  tmpfs  
tmpfs              /run/user/1000      1.6G     0.0G     1.6G    0%  tmpfs  
tmpfs              /sys/fs/cgroup      7.8G     0.0G     7.8G    0%  tmpfs  
/dev/sda1          /var/lib/docker   901.2G   188.3G   667.1G   26%  ext4   

di 默认的输出就是比较人性化的了。

看 di 的使用介绍 man di 就会发现 di 是这么介绍自己的

> di Displays usage information on mounted filesystems.  Block values are reported in a human readable format.  If the user or group has  a  disk  quota,  the  values  reported  are adjusted according the quotas that apply to the user.

一些简单的使用

A 选项打印所有挂载设备

di -A
Mount                fs Type Filesystem 
	Options                                                           
	    Size     Used     Free %Used  %Free 
	    Size     Used    Avail %Used  %Free 
	    Size     Used    Avail %Used  
	   Inodes     IUsed     IFree %IUsed
/                    ext4    /dev/sda1  
	rw,relatime,errors=remount-ro,data=ordered                        
	  901.2G   188.3G   712.9G   21%    79%  
	  901.2G   234.1G   667.1G   26%    74%  
	  855.4G   188.3G   667.1G   22%  
	 60014592   1372538  58642054    2% 
/dev/shm             tmpfs   tmpfs      
	rw,nosuid,nodev                                                   
	    7.8G     0.1G     7.6G    2%    98%  
	    7.8G     0.1G     7.6G    2%    98%  
	    7.8G     0.1G     7.6G    2%  
	  2036725       741   2035984    0% 
/run                 tmpfs   tmpfs      
	rw,nosuid,noexec,relatime,size=1629380k,mode=755                  
	    1.6G     0.1G     1.5G    4%    96%  
	    1.6G     0.1G     1.5G    4%    96%  
	    1.6G     0.1G     1.5G    4%  
	  2036725       777   2035948    0% 
/run/cgmanager/fs    tmpfs   cgmfs      
	rw,relatime,size=100k,mode=755                                    
	    0.1M     0.0M     0.1M    0%   100%  
	    0.1M     0.0M     0.1M    0%   100%  
	    0.1M     0.0M     0.1M    0%  
	  2036725        14   2036711    0% 
/run/lock            tmpfs   tmpfs      
	rw,nosuid,nodev,noexec,relatime,size=5120k                        
	    5.0M     0.0M     5.0M    0%   100%  
	    5.0M     0.0M     5.0M    0%   100%  
	    5.0M     0.0M     5.0M    0%  
	  2036725         4   2036721    0% 
/run/user/0          tmpfs   tmpfs      
	rw,nosuid,nodev,relatime,size=1629380k,mode=700                   
	    1.6G     0.0G     1.6G    0%   100%  
	    1.6G     0.0G     1.6G    0%   100%  
	    1.6G     0.0G     1.6G    0%  
	  2036725         4   2036721    0% 
/run/user/1000       tmpfs   tmpfs      
	rw,nosuid,nodev,relatime,size=1629380k,mode=700,uid=1000,gid=1000 
	    1.6G     0.0G     1.6G    0%   100%  
	    1.6G     0.0G     1.6G    0%   100%  
	    1.6G     0.0G     1.6G    0%  
	  2036725        36   2036689    0% 
/sys/fs/cgroup       tmpfs   tmpfs      
	rw,mode=755                                                       
	    7.8G     0.0G     7.8G    0%   100%  
	    7.8G     0.0G     7.8G    0%   100%  
	    7.8G     0.0G     7.8G    0%  
	  2036725        18   2036707    0% 
/var/lib/docker/aufs ext4    /dev/sda1  
	rw,relatime,errors=remount-ro,data=ordered                        
	  901.2G   188.3G   712.9G   21%    79%  
	  901.2G   234.1G   667.1G   26%    74%  
	  855.4G   188.3G   667.1G   22%  
	 60014592   1372538  58642054    2% 

c 选项逗号分割

使用 -c 选项分割输出

di -c
s,m,b,u,v,p,T
"/dev/sda1","/","901.2G","188.3G","667.1G",26%,"ext4"
"tmpfs","/dev/shm","7.8G","0.1G","7.6G",2%,"tmpfs"
"tmpfs","/run","1.6G","0.1G","1.5G",4%,"tmpfs"
"cgmfs","/run/cgmanager/fs","0.1M","0.0M","0.1M",0%,"tmpfs"
"tmpfs","/run/lock","5.0M","0.0M","5.0M",0%,"tmpfs"
"tmpfs","/run/user/0","1.6G","0.0G","1.6G",0%,"tmpfs"
"tmpfs","/run/user/1000","1.6G","0.0G","1.6G",0%,"tmpfs"
"tmpfs","/sys/fs/cgroup","7.8G","0.0G","7.8G",0%,"tmpfs"
"/dev/sda1","/var/lib/docker/aufs","901.2G","188.3G","667.1G",26%,"ext4"

c 是 --csv-output 的缩写,为了便于程序解析

t 参数增加统计行

-t 参数在最后增加统计行

di -t
Filesystem         Mount               Size     Used    Avail %Used  fs Type
/dev/sda1          /                 901.2G   188.4G   667.0G   26%  ext4   
tmpfs              /dev/shm            7.8G     0.1G     7.6G    2%  tmpfs  
tmpfs              /run                1.6G     0.1G     1.5G    4%  tmpfs  
cgmfs              /run/cgmanager/     0.1M     0.0M     0.1M    0%  tmpfs  
tmpfs              /run/lock           5.0M     0.0M     5.0M    0%  tmpfs  
tmpfs              /run/user/0         1.6G     0.0G     1.6G    0%  tmpfs  
tmpfs              /run/user/1000      1.6G     0.0G     1.6G    0%  tmpfs  
tmpfs              /sys/fs/cgroup      7.8G     0.0G     7.8G    0%  tmpfs  
/dev/sda1          /var/lib/docker   901.2G   188.4G   667.0G   26%  ext4   
                   Total               1.8T     0.4T     1.3T   26%      

s 参数对结果排序

di -s 默认更具 mount point 输出

  • di -sm 默认 mount pont
  • di -sn 不排序,按照挂载表 /etc/fstab 中顺序
  • di -ss 按照特殊设备
  • di -st 根据 filesystem type
  • di -sr 逆序输出

排序方式可以组合使用,如:di –stsrm :按照类型、设备、挂载点逆序排序。 di –strsrm :按照类型、设备逆序、挂载点逆序排序。

f 选项自定义格式

di -fM
Mount               
/                   
/dev/shm            
/run                
/run/cgmanager/fs   
/run/lock           
/run/user/0         
/run/user/1000      
/sys/fs/cgroup      
/var/lib/docker/aufs

只打印 mount point

更多的 f 的选项可以直接参看 man di

总结

虽然 di 提供了比 df 更多更强大的功能,但是也有其缺点,大部分的 Linux 发行版默认是没有预装的。


2017-10-16 linux , 磁盘管理 , disk , df

电子书

最近文章

  • 使用 assh 来管理 SSH config 前两天一直在思考如何管理我的 SSH config 配置,最后的解决办法就是通过 git 版本管理起来。但这两天由冒出一个新的问题,那就是经常在国内直连 aws 或者 oracle 的机器时 ssh 连不上,但是通过国内的 VPS 中转就非常快,那这就意味着,我每一次连接国外的机器时必须先登录腾讯云的机器,然后在从腾讯云的机器上连过去,有些麻烦,但那天在 Twitter 上看到有人分享了一个 SSH 管理的命令行工具 assh,大致的看了一下使用简介,通过配置就可以完美的解决这个问题。
  • 备份和恢复从 Chrome Webstore 中下架的 Google Chrome Extension 这两天重装系统同步 Chrome 的数据才发现,我一直使用的 Dream Afar New Tab 这个我用了很久的扩展从 Chrome Webstore 消失了,不清楚是 Google 主动下架,还是作者很久没有更新被 Webstore 下了还是为什么。但这个扩展经过了很多的 Chrome 版本依然运行良好至今为止都能每天给我提供世界不同地方的美景。
  • Docker 网络与容器互联 简单整理一下 Docker 中 network 子命令,以及 docker 中相关 network 方面的内容。
  • MacBook Pro 初始设置记录 这里就简单的记录一下我从 Linux Mint 迁移到 MacOS 根据我的个人需求来初始化新的 MacBook Pro 的一些设置,和一些基本的感想。下面的内容会按照我自身的需求出发,我会列举我想要的功能然后在此基础上我需要借助哪些工具来实现。在切换到 MacBook Pro 之前,我使用了大约 6 年多的 Linux Mint,我已经有一套我自己的 Workflow,在切换到 Mac OS 之前我就在想哪一些的事情我是必须有 Mac 的软硬件才能做到,并且很提高某一方面的效率的,我列了一些
  • 多设备间同步 ssh 配置及密钥 ssh 客户端会在用户目录 ~/.ssh/ 目录下存放配置信息 (~/.ssh/config) 和公钥和私钥,如果有多个设备不同设备间的同步和管理就会成为一个比较头疼的问题。我在 Reddit 上抛出这个问题 后,我本来想的是通过 git 版本控制来进行管理,但有人说因为公钥和私钥都是二进制的文件,其实没有必要使用 git,任何一个同步工具就能够解决。