FFmpeg

https://www.jianshu.com/p/7ed3be01228b
FFmpeg分为3个版本:Static、 Shared、 Dev
前两个版本可以直接在命令行中使用。包含了三个exe:ffmpeg.exe,ffplay.exe,ffprobe.exe
Static版本中的exe体积较大,那是因为相关的Dll都已经编译进exe里面去了。
Shared版本中exe的体积相对小很多,是因为它们运行的时候还需要到相关的dll中调用相应的功能
Dev版本用于开发,里面包含了库文件xxx.lib以及头文件xxx.h


ffmpeg -i 1.mp4 -q 0 -c:v hevc -aq 0 -c:a aac 2.mp4

FFmpeg视频转码技巧之-crf参数(H.264篇)

一般用libx264来压缩视频就可以了
ffmpeg -i D:\qiniu\dxdjy_20180608_cn.mp4 -c:a copy -c:v libx264 -profile:v high -preset slower -crf:v 21 D:\qiniu\dxdjy_20180608_cn_small.mp4

https://blog.csdn.net/happydeer/article/details/52610060

ffmpeg -i MVI_7274.MOV -vcodec libx264 -preset fast -crf 20 -y -vf "scale=1920:-1" -acodec libmp3lame -ab 128k a.mp4

-preset:指定编码的配置。x264编码算法有很多可供配置的参数,不同的参数值会导致编码的速度大相径庭,甚至可能影响质量。为了免去用户了解算法,然后手工配置参数的麻烦。x264提供了一些预设值,而这些预设值可以通过preset指定。这些预设值有包括:ultrafast,superfast,veryfast,faster,fast,medium,slow,slower,veryslow和placebo。ultrafast编码速度最快,但压缩率低,生成的文件更大,placebo则正好相反。x264所取的默认值为medium。需要说明的是,preset主要是影响编码的速度,并不会很大的影响编码出来的结果的质量。压缩高清电影时,我一般用slow或者slower,当你的机器性能很好时也可以使用veryslow,不过一般并不会带来很大的好处。

-crf:这是最重要的一个选项,用于指定输出视频的质量,取值范围是0-51,默认值为23,数字越小输出视频的质量越高。这个选项会直接影响到输出视频的码率。一般来说,压制480p我会用20左右,压制720p我会用16-18,1080p我没尝试过。个人觉得,一般情况下没有必要低于16。最好的办法是大家可以多尝试几个值,每个都压几分钟,看看最后的输出质量和文件大小,自己再按需选择。

发表在 码农日常 | 留下评论

vsftp错误:553 Could not create file解决方法

首先目录保证是ftp用户,然后用户组也是ftp的用户组

sudo chmod -R g+w /var/www/ftpuserfolder

发表在 码农日常 | 留下评论

Unable to lock the administration directory (/var/lib/dpkg/) is another process using it?

https://askubuntu.com/questions/15433/unable-to-lock-the-administration-directory-var-lib-dpkg-is-another-process

ps -e | grep -e apt -e adept | grep -v grep

kill -9 processnumber

sudo rm /var/lib/apt/lists/lock

sudo rm /var/cache/apt/archives/lock

sudo rm /var/lib/dpkg/lock

 

发表在 码农日常 | 标签为 | 留下评论

Web服务器Nginx多方位优化策略

http://blog.csdn.net/enweitech/article/details/51500268

一.     安装

(1)  精简模块

Nginx由于不断添加新的功能,附带的模块也越来越多。很多操作系统厂商为了用户方便安装管理,都增加了rpm、deb或者其他自有格式软件包,可以本地甚至在线安装。不过我不太建议使用这种安装方式。这虽然简化了安装,在线安装甚至可以自动解决软件依赖关系,但是安装后软件的文件布局过于分散,不便管理维护;同时也正是由于存在软件包之间的依赖关系,导致当有安全漏洞、或者其它问题,想要通过更新升级Nginx新版本时却发现yum、deb源还未发布新版本(一般都落后于官网发布的软件版本)。最重要的是采用非源码编译安装的方式,默认会添加入许多模块,比如邮件相关、uwsgi、memcache等等,很多网站运行时这些模块根本未用到,虽然平时占用的资源很小,但是仍然可能是压弯骆驼的一根稻草。各种非必需模块默认安装运行的同时,也给Web系统带来了安全隐患。尽量保持软件的轻装上阵,是每个运维应当尽力做到的,所以我建议一般常用的服务器软件使用源码编译安装管理。。我一般使用的编译参数如下,PHP相关模块fastcgi被保留用作后文优化说明,:

编译参数根据网站是否真正用到的原则增添或者减少,比如我们公司如果需要用到ssi模块,从而能够实现访问shtml页面,可以将第17行删除,那么Nginx将默认安装。大家可以通过运行 “./configure –help” 查看编译帮助,决定是否需要安装哪些模块。

(2)  GCC编译参数优化 [可选项】

GCC总共提供了5级编译优化级别:

-O0: 无优化。

-O和-O1: 使用能减少目标代码尺寸以及执行时间并且不会使编译时间明显增加的优化。在编译大型程序的时候会显著增加编译时内存的使用。

-O2: 包含-O1的优化并增加了不需要在目标文件大小和执行速度上进行折衷的优化。编译器不执行循环展开以及函数内联。此选项将增加编译时间和目标文件的执行性能。

-Os: 可以看成 -O2.5,专门优化目标文件大小,执行所有的不增加目标文件大小的-O2优化选项,并且执行专门减小目标文件大小的优化选项。适用于磁盘空间紧张时使用。但有可能有未知的问题发生,况且目前硬盘容量很大,常用程序无必要使用。

-O3: 打开所有 -O2 的优化选项外增加 -finline-functions、-funswitch-loops、-fgcse-after-reload 优化选项。相对于 -O2 性能并未有较多提高,编译时间也最长,生成的目标文件也更大更占内存,有时性能不增反而降低,甚至产生不可预知的问题(包括错误),所以并不被大多数软件安装推荐,除非有绝对把握方可使用此优化级别。

修改GCC编译参数,提高编译优化级别,此方法适用于所有通过GCC编译安装的程序,不止Nginx。稳妥起见用 -O2,这也是大多数软件编译推荐的优化级别。查看Nginx源码文件 auto/cc/gcc,搜索NGX_GCC_OPT,默认GCC编译参数为-O,可以直接修改内容为NGX_GCC_OPT=”-O2″或者在 ./configure配置时添加–with-cc-opt=’-O2’选项。


二.      配置

应用服务器的性能优化主要在合理使用CPU、内存、磁盘IO和网络IO四个方面,现在我们从Nginx配置文件 nginx.conf 入手进行优化:

(1)  工作进程数的选择

指令:worker_processes

定义了Nginx对外提供web服务时的工作进程数。最优值取决于许多因素,包括(但不限于)CPU核心的数量、存储数据的硬盘数量及负载模式。不能确定的时候,将其设置为可用的CPU内核数将是一个好的开始(设置为“auto”将尝试自动检测它)。Shell执行命令  ps ax | grep “nginx: worker process” | grep -v “grep” 可以看到运行中的Nginx工作进程数,一般建议设置成服务器逻辑核心数,Shell执行命令 cat /proc/cpuinfo | grep processor | wc -l 可以检测出服务器逻辑核心总数,偷懒可以直接写auto,Nginx自适应。

(2)  是否绑定CPU

指令:worker_cpu_affinity

绑定工作进程到对应CPU核心,Nginx默认未开启CPU绑定。目前的服务器一般为多核CPU,当并发很大时,服务器各个CPU的使用率可能出现严重不均衡的局面,这时候可以考虑使用CPU绑定,以达到CPU使用率相对均匀的状态,充分发挥多核CPU的优势。top、htop等程序可以查看所有CPU核心的使用率状况。绑定样例:

(3)  打开文件数限制

指令:worker_rlimit_nofile

设定了每个Nginx工作进程打开的最大文件数,受限于系统的用户进程打开文件数限制,未设置则使用系统默认值。理论上应该设置为当前Shell启动进程的最大打开文件数除以Nginx的工作进程数。由于Nginx的工作进程打开文件数并不一完全均匀,所以可以将其设置成Shell启动进程的最大打开文件数。Shell执行命令 ulimit -n 可以查看当前登录Shell会话最大打开文件数数限制。Linux系统用户进程默认同时打开文件最大数为1024,这个值太小,访问量稍大就报“too many open files”。Shell执行命令先修改用户打开文件数限制:

然后添加入/etc/profile如下两行内容,修改所有Shell和通过Shell启动的进程打开文件数限制:

Shell执行命令使当前Shell临时会话立即生效:

(4) 惊群问题

指令:accept_mutex

如果 accept_mutex 指令值为 on 启用,那么将轮流唤醒一个工作进程接收处理新的连接,其余工作进程继续保持睡眠;如果值为 off 关闭,那么将唤醒所有工作进程,由系统通过use指令指定的网络IO模型调度决定由哪个工作进程处理,未接收到连接请求的工作进程继续保持睡眠,这就是所谓的“惊群问题”。Web服务器Apache的进程数很多,成百上千也是时有的事,“惊群问题”也尤为明显。Nginx为了稳定,参数值保守的设置为 on 开启状态。可以将其设置成Off 提高性能和吞吐量,但这样也会带来上下文切换增多或者负载升高等等其它资源更多消耗的后果。

(5)  网络IO模型

指令:use

定义了Nginx设置用于复用客户端线程的轮询方法(也可称多路复用网络IO模型)。这自然是选择效率更高的优先,Linux 2.6+内核推荐使用epoll,FreeBSD推荐使用kqueue,安装时Nginx会自动选择。

(6)  连接数

指令:worker_connections

定义了Nginx一个工作进程的最大同时连接数,不仅限于客户端连接,包括了和后端被代理服务器等其他的连接。官网文档还指出了该参数值不能超过 worker_rlimit_nofile 值,所以建议设置成和 worker_rlimit_nofile 值相等。

(7)  打开文件缓存

指令:open_file_cache

开启关闭打开文件缓存,默认值 off 关闭,强烈建议开启,可以避免重新打开同一文件带来的系统开销,节省响应时间。如需开启必须后接参数 max=数字,设置缓存元素的最大数量。当缓存溢出时,使用LRU(最近最少使用)算法删除缓存中的元素;可选参数 inactive=时间 设置超时,在这段时间内缓存元素如果没有被访问,将从缓存中删除。示例:open_file_cache max=65536  inactive=60s。

指令:open_file_cache_valid

设置检查open_file_cache缓存的元素的时间间隔。

指令:open_file_cache_min_uses

设置在由open_file_cache指令的inactive参数配置的超时时间内, 文件应该被访问的最小次数。如果访问次数大于等于此值,文件描述符会保留在缓存中,否则从缓存中删除。

(8)  日志相关

指令:access_log 和 error_log

当并发很大时,Nginx的访问日志和错误日志的保存肯定会造成对磁盘的大量读写,也将影响Nginx的性能。并发量越大,IO越高。这时候可以考虑关闭访问日志和错误日志,或者将日志保存到tmpfs文件系统里,或者减少保存的访问日志条目和错误日志的级别,从而避免磁盘IO的影响。关闭日志使用 access_log off。如必须保存日志,可以按每日或者每时或者其它时间段对日志做切割,这也可以减小IO,虽然可能效果不是特别大,不过因为日志文件尺寸变小了很多,也方便查阅或归档分析日志。一般线上环境建议错误日志设置为 error 或者 crit。自定义访问日志的条目和错误日志的级别,详细信息可以参阅官网或者网上其它文档,按需修改。

(9)  隐藏Nginx版本号

指令:server_tokens

开启或关闭“Server”响应头中输出的Nginx版本号。推介设置为 off,关闭显示响应头的版本号,对性能的提高有小小的裨益,主要还是为了安全起见,不被骇客找到版本号对应的漏洞,从而被攻击。

(10) 压缩相关

指令:gzip

Nginx默认开启了gzip压缩功能。有可能很多人认为,开启gzip压缩会增加CPU的处理时间和负载。但是经过我们网站的测试发现,关闭了gzip压缩功能的Nginx虽然减少了CPU计算,节省了服务器的响应时间,但网站页面总体响应时间反而加长了,原因在于js和css、xml、json、html等等这些静态文件的数据传输时间的增长大大超过了服务器节省出来的响应时间,得不偿失。gzip on 开启压缩后,大约可以减少75%的文件尺寸,不但节省了比较多的带宽流量,也提高了页面的整体响应时间。所有建议还是开启。当然也不是所有的静态文件都需要压缩,比如静态图片和PDF、视频,文件本身就应当做压缩处理后保存到服务器。这些文件再次使用gzip压缩,压缩的比例并不高,甚至适得其反,压缩后文件尺寸增大了。CPU压缩处理这些静态文件增加占用的服务器响应时间绝大部分时候会超过了被压缩减小的文件尺寸减少的数据传输时间,不划算。是否需要对Web网站开启压缩,以及对哪些文件过滤压缩,大家可以通过使用HttpWatch、Firebug等等网络分析工具对比测试。

指令:gzip_comp_level

指定压缩等级,其值从1到9,数字越大,压缩率越高,越消耗CPU,负载也越高。9等级无疑压缩率最高,压缩后的文件尺寸也最小,但也是最耗CPU资源,负载最高,速度最慢的,这对于用户访问有时是无法忍受的。一般推荐使用1-4等级,比较折衷的方案。我们公司网站使用等级2。

指令:gzip_min_length

指定压缩的文件最小尺寸,单位 bytes 字节,低于该值的不压缩,超过该值的将被压缩。我们网站设置为1k,太小的文件没必要压缩,压缩过小尺寸文件带来增加的CPU消耗时间和压缩减少的文件尺寸降低的数据下载时间互相抵消,并有可能增加总体的响应时间。

指令:gzip_types

指定允许压缩的文件类型,Nginx配置目录 conf 下的 mime.types 文件存放了Nginx支持的文件类型,text/html类型文件,文件后缀为html htm shtml默认压缩。推荐配置:gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript。

(11) 浏览器缓存

指令:expires

设置HTTP应答中的“Expires”和“Cache-Control”头标。”Expires”一般结合”Last-Modified”使用。当设置了合理的expires配置时,浏览器第一次访问Web页面元素,会下载页面中的的静态文件到本机临时缓存目录下。第二次及之后再次访问相同URL时将发送带头标识”If-Modified-Since”和本地缓存文件时间属性值的请求给服务器,服务器比对服务器本地文件时间属性值,如果未修改,服务器直接返回http 304状态码,浏览器直接调用本地已缓存的文件;如果时间属性值修改了,重新发送新文件。这样就避免了从服务器再次传送文件内容,减小了服务器压力,节省了带宽,同时也提高了用户访问速度,一举三得。指令后接数字加时间单位,即为缓存过期时间;-1 表示永远过期,不缓存。强烈建议添加expires配置,过期时间的选择具体分析。我们公司的部分Nginx配置如下:

或者统一将静态文件放在固定目录下再对目录做location和expires,示例:

(12) 持久连接

指令:keepalive_timeout

启用Http的持久连接Keepalive属性,复用之前已建立的TCP连接接收请求、发送回应,减少重新建立TCP连接的资源时间开销。在此的建议是当网站页面内容以静态为主时,开启持久连接;若主要是动态网页,且不能被转化为静态页面,则关闭持久连接。后接数字和时间单位符号。正数为开启持久连接,0关闭。

(13) 减少HTTP请求次数

网站页面中存在大量的图片、脚本、样式表、Flash等静态元素,减少访问请求次数最大的优点就是减少用户首次访问页面的加载时间。可以采用合并相同类型文件为一个文件的办法减少请求次数。这其实属于Web前端优化范畴,应当由Web前段工程师做好相关静态文件的规划管理,而不是由运维来做。不过Nginx也可以通过安装阿里巴巴提供的Concat或者Google的PageSpeed模块实现这个合并文件的功能。我们公司并未使用合并功能,具体安装配置信息请查询网上相关文档,这里不再累述。Concat源代码网址:https://github.com/alibaba/nginx-http-concat/,PageSpeed源代码网址:https://github.com/pagespeed/ngx_pagespeed。

(14) PHP相关

Nginx不能直接解析PHP代码文件,需要调用FastCGI接口转给PHP解释器执行,然后将结果返回给Nginx。PHP优化本文暂不介绍。Nginx可以开启FastCGI的缓存功能,从而提高性能。

指令:fastcgi_temp_path

定义FastCGI缓存文件保存临时路径。

指令:fastcgi_cache_path

定义FastCGI缓存文件保存路径和缓存的其它参数。缓存数据以二进制数据文件形式存储,缓存文件名和key都是通过对访问URL使用MD5计算获得的结果。缓存文件先保存至fastcgi_temp_path指定的临时目录下,然后通过重命名操作移至fastcgi_cache_path指定的缓存目录。levels指定了目录结构,子目录数以16为基数;keys_zone指定了共享内存区名和大小,用于保存缓存key和数据信息;inactive指定了缓存数据保存的时间,当这段时间内未被访问,将被移出;max_size指定了缓存使用的最大磁盘空间,超过容量时将最近最少使用数据删除。建议fastcgi_temp_path和fastcgi_cache_path设为同一分区,同分区移动操作效率更高。示例:

示例中使用/tmp/fastcgi_temp作为FastCGI缓存的临时目录;/tmp/fastcgi_cache作为FastCGI缓存保存的最终目录;一级子目录为16的一次方16个,二级子目录为16的2次方256个;共享内存区名为cache_fastcgi,占用内存128MB;缓存过期时间为30分钟;缓存数据保存于磁盘的最大空间大小为1GB。

指令:fastcgi_cache_key

定义FastCGI缓存关键字。启用FastCGI缓存必须加上这个配置,不然访问所有PHP的请求都为访问第一个PHP文件URL的结果。

指令:fastcgi_cache_valid

为指定的Http状态码指定缓存时间。

指令:fastcgi_cache_min_uses

指定经过多少次请求相同的URL将被缓存。

指令:fastcgi_cache_use_stale

指定当连接FastCGI服务器发生错误时,哪些情况使用过期数据回应。

指令:fastcgi_cache

缓存使用哪个共享内存区。

我常用nginx.conf模板,大家根据情况做适当修改:


三.        内核

Linux内核参数部分默认值不适合高并发,一般临时方法可以通过调整/Proc文件系统,或者直接修改/etc/sysctl.conf配置文件永久保存。调整/Proc文件系统,系统重启后还原至默认值,所以不推荐。Linux内核调优,主要涉及到网络和文件系统、内存等的优化,下面是我常用的内核调优配置:

详细说明大家可以查看我的Linux内核优化文章:http://dongsong.blog.51cto.com/916653/1631085


四.        架构

Nginx的最大优势在于处理静态文件和代理转发功能,支持7层负载均衡和故障隔离。 动静分离是每个网站发展到一定规模之后必然的结果。静态请求则应当最好将其拆分,并启用独立的域名,既便于管理的需要,也便于今后能够快速支持CDN。如果一台Nginx性能无法满足,则可以考虑在Nginx前端添加LVS负载均衡,或者F5等硬件负载均衡(费用昂贵,适合土豪公司单位),由多台Nginx共同分担网站请求。还可以考虑结合Varnish或者Squid缓存静态文件实现类似CDN功能。新版Nginx目前已经支持直接读写Memcache,可以编译安装时候选择添加此类模块,从而节省了转交给PHP或者JPS等动态程序服务器处理时间,提高效率的同时,减小了动态服务器的负载

发表在 码农日常 | 标签为 | 留下评论

对RESTful API的个人看法

http://blog.csdn.net/enweitech/article/details/79208321

 

什么是REST?

可以总结为一句话:REST是所有Web应用都应该遵守的架构设计指导原则。
Representational State Transfer,翻译是”表现层状态转化”。
面向资源是REST最明显的特征,对于同一个资源的一组不同的操作。资源是服务器上一个可命名的抽象概念,资源是以名词为核心来组织的,首先关注的是名词。REST要求,必须通过统一的接口来对资源执行各种操作。对于每个资源只能执行一组有限的操作。(7个HTTP方法:GET/POST/PUT/DELETE/PATCH/HEAD/OPTIONS)

什么是RESTful API?

符合REST架构设计的API。

1. 什么是REST

 

REST全称是Representational State Transfer,中文意思是表述(编者注:通常译为表征)性状态转移。 它首次出现在2000年Roy Fielding的博士论文中,Roy Fielding是HTTP规范的主要编写者之一。 他在论文中提到:”我这篇文章的写作目的,就是想在符合架构原理的前提下,理解和评估以网络为基础的应用软件的架构设计,得到一个功能强、性能好、适宜通信的架构。REST指的是一组架构约束条件和原则。” 如果一个架构符合REST的约束条件和原则,我们就称它为RESTful架构。

REST本身并没有创造新的技术、组件或服务,而隐藏在RESTful背后的理念就是使用Web的现有特征和能力, 更好地使用现有Web标准中的一些准则和约束。虽然REST本身受Web技术的影响很深, 但是理论上REST架构风格并不是绑定在HTTP上,只不过目前HTTP是唯一与REST相关的实例。 所以我们这里描述的REST也是通过HTTP实现的REST。

2. 理解RESTful

要理解RESTful架构,需要理解Representational State Transfer这个词组到底是什么意思,它的每一个词都有些什么涵义。

下面我们结合REST原则,围绕资源展开讨论,从资源的定义、获取、表述、关联、状态变迁等角度,列举一些关键概念并加以解释。

  • 资源与URI
  • 统一资源接口
  • 资源的表述
  • 资源的链接
  • 状态的转移

2. 1 资源与URI

REST全称是表述性状态转移,那究竟指的是什么的表述? 其实指的就是资源。任何事物,只要有被引用到的必要,它就是一个资源。资源可以是实体(例如手机号码),也可以只是一个抽象概念(例如价值) 。下面是一些资源的例子:

  • 某用户的手机号码
  • 某用户的个人信息
  • 最多用户订购的GPRS套餐
  • 两个产品之间的依赖关系
  • 某用户可以办理的优惠套餐
  • 某手机号码的潜在价值

要让一个资源可以被识别,需要有个唯一标识,在Web中这个唯一标识就是URI(Uniform Resource Identifier)。

URI既可以看成是资源的地址,也可以看成是资源的名称。如果某些信息没有使用URI来表示,那它就不能算是一个资源, 只能算是资源的一些信息而已。URI的设计应该遵循可寻址性原则,具有自描述性,需要在形式上给人以直觉上的关联。这里以github网站为例,给出一些还算不错的URI:

下面让我们来看看URI设计上的一些技巧:

  • 使用_或-来让URI可读性更好

曾经Web上的URI都是冰冷的数字或者无意义的字符串,但现在越来越多的网站使用_或-来分隔一些单词,让URI看上去更为人性化。 例如国内比较出名的开源中国社区,它上面的新闻地址就采用这种风格, 如http://www.oschina.net/news/38119/oschina-translate-reward-plan。

  • 使用/来表示资源的层级关系

例如上述/git/git/commit/e3af72cdafab5993d18fae056f87e1d675913d08就表示了一个多级的资源, 指的是git用户的git项目的某次提交记录,又例如/orders/2012/10可以用来表示2012年10月的订单记录。

  • 使用?用来过滤资源

很多人只是把?简单的当做是参数的传递,很容易造成URI过于复杂、难以理解。可以把?用于对资源的过滤, 例如/git/git/pulls用来表示git项目的所有推入请求,而/pulls?state=closed用来表示git项目中已经关闭的推入请求, 这种URL通常对应的是一些特定条件的查询结果或算法运算结果。

  • ,或;可以用来表示同级资源的关系

有时候我们需要表示同级资源的关系时,可以使用,或;来进行分割。例如哪天github可以比较某个文件在随意两次提交记录之间的差异,或许可以使用/git/git /block-sha1/sha1.h/compare/e3af72cdafab5993d18fae056f87e1d675913d08;bd63e61bdf38e872d5215c07b264dcc16e4febca作为URI。 不过,现在github是使用…来做这个事情的,例如/git/git/compare/master…next。

2. 2 统一资源接口

RESTful架构应该遵循统一接口原则,统一接口包含了一组受限的预定义的操作,不论什么样的资源,都是通过使用相同的接口进行资源的访问。接口应该使用标准的HTTP方法如GET,PUT和POST,并遵循这些方法的语义。

如果按照HTTP方法的语义来暴露资源,那么接口将会拥有安全性和幂等性的特性,例如GET和HEAD请求都是安全的, 无论请求多少次,都不会改变服务器状态。而GET、HEAD、PUT和DELETE请求都是幂等的,无论对资源操作多少次, 结果总是一样的,后面的请求并不会产生比第一次更多的影响。

下面列出了GET,DELETE,PUT和POST的典型用法:

GET

  • 安全且幂等
  • 获取表示
  • 变更时获取表示(缓存)
  • 200(OK) – 表示已在响应中发出
  • 204(无内容) – 资源有空表示
  • 301(Moved Permanently) – 资源的URI已被更新
  • 303(See Other) – 其他(如,负载均衡)
  • 304(not modified)- 资源未更改(缓存)
  • 400 (bad request)- 指代坏请求(如,参数错误)
  • 404 (not found)- 资源不存在
  • 406 (not acceptable)- 服务端不支持所需表示
  • 500 (internal server error)- 通用错误响应
  • 503 (Service Unavailable)- 服务端当前无法处理请求

POST

  • 不安全且不幂等
  • 使用服务端管理的(自动产生)的实例号创建资源
  • 创建子资源
  • 部分更新资源
  • 如果没有被修改,则不过更新资源(乐观锁)
  • 200(OK)- 如果现有资源已被更改
  • 201(created)- 如果新资源被创建
  • 202(accepted)- 已接受处理请求但尚未完成(异步处理)
  • 301(Moved Permanently)- 资源的URI被更新
  • 303(See Other)- 其他(如,负载均衡)
  • 400(bad request)- 指代坏请求
  • 404 (not found)- 资源不存在
  • 406 (not acceptable)- 服务端不支持所需表示
  • 409 (conflict)- 通用冲突
  • 412 (Precondition Failed)- 前置条件失败(如执行条件更新时的冲突)
  • 415 (unsupported media type)- 接受到的表示不受支持
  • 500 (internal server error)- 通用错误响应
  • 503 (Service Unavailable)- 服务当前无法处理请求

PUT

  • 不安全但幂等
  • 用客户端管理的实例号创建一个资源
  • 通过替换的方式更新资源
  • 如果未被修改,则更新资源(乐观锁)
  • 200 (OK)- 如果已存在资源被更改
  • 201 (created)- 如果新资源被创建
  • 301(Moved Permanently)- 资源的URI已更改
  • 303 (See Other)- 其他(如,负载均衡)
  • 400 (bad request)- 指代坏请求
  • 404 (not found)- 资源不存在
  • 406 (not acceptable)- 服务端不支持所需表示
  • 409 (conflict)- 通用冲突
  • 412 (Precondition Failed)- 前置条件失败(如执行条件更新时的冲突)
  • 415 (unsupported media type)- 接受到的表示不受支持
  • 500 (internal server error)- 通用错误响应
  • 503 (Service Unavailable)- 服务当前无法处理请求

DELETE

  • 不安全但幂等
  • 删除资源
  • 200 (OK)- 资源已被删除
  • 301 (Moved Permanently)- 资源的URI已更改
  • 303 (See Other)- 其他,如负载均衡
  • 400 (bad request)- 指代坏请求
  • 404 (not found)- 资源不存在
  • 409 (conflict)- 通用冲突
  • 500 (internal server error)- 通用错误响应
  • 503 (Service Unavailable)- 服务端当前无法处理请求

下面我们来看一些实践中常见的问题:

  • POST和PUT用于创建资源时有什么区别?

POST和PUT在创建资源的区别在于,所创建的资源的名称(URI)是否由客户端决定。 例如为我的博文增加一个java的分类,生成的路径就是分类名/categories/java,那么就可以采用PUT方法。不过很多人直接把POST、GET、PUT、DELETE直接对应上CRUD,例如在一个典型的rails实现的RESTful应用中就是这么做的。

我认为,这是因为rails默认使用服务端生成的ID作为URI的缘故,而不少人就是通过rails实践REST的,所以很容易造成这种误解。

  • 客户端不一定都支持这些HTTP方法吧?

的确有这种情况,特别是一些比较古老的基于浏览器的客户端,只能支持GET和POST两种方法。

在实践上,客户端和服务端都可能需要做一些妥协。例如rails框架就支持通过隐藏参数_method=DELETE来传递真实的请求方法, 而像Backbone这样的客户端MVC框架则允许传递_method传输和设置X-HTTP-Method-Override头来规避这个问题。

  • 统一接口是否意味着不能扩展带特殊语义的方法?

统一接口并不阻止你扩展方法,只要方法对资源的操作有着具体的、可识别的语义即可,并能够保持整个接口的统一性。

像WebDAV就对HTTP方法进行了扩展,增加了LOCK、UPLOCK等方法。而github的API则支持使用PATCH方法来进行issue的更新,例如:

PATCH /repos/:owner/:repo/issues/:number

不过,需要注意的是,像PATCH这种不是HTTP标准方法的,服务端需要考虑客户端是否能够支持的问题。

  • 统一资源接口对URI有什么指导意义?

统一资源接口要求使用标准的HTTP方法对资源进行操作,所以URI只应该来表示资源的名称,而不应该包括资源的操作。

通俗来说,URI不应该使用动作来描述。例如,下面是一些不符合统一接口要求的URI:

  • GET /getUser/1
  • POST /createUser
  • PUT /updateUser/1
  • DELETE /deleteUser/1

如果GET请求增加计数器,这是否违反安全性?

安全性不代表请求不产生副作用,例如像很多API开发平台,都对请求流量做限制。像github,就会限制没有认证的请求每小时只能请求60次。

但客户端不是为了追求副作用而发出这些GET或HEAD请求的,产生副作用是服务端”自作主张”的。

另外,服务端在设计时,也不应该让副作用太大,因为客户端认为这些请求是不会产生副作用的。

  • 直接忽视缓存可取吗?

即使你按各个动词的原本意图来使用它们,你仍可以轻易禁止缓存机制。 最简单的做法就是在你的HTTP响应里增加这样一个报头: Cache-control: no-cache。 但是,同时你也对失去了高效的缓存与再验证的支持(使用Etag等机制)。

对于客户端来说,在为一个REST式服务实现程序客户端时,也应该充分利用现有的缓存机制,以免每次都重新获取表示。

  • 响应代码的处理有必要吗?

HTTP的响应代码可用于应付不同场合,正确使用这些状态代码意味着客户端与服务器可以在一个具备较丰富语义的层次上进行沟通。

例如,201(”Created”)响应代码表明已经创建了一个新的资源,其URI在Location响应报头里。

假如你不利用HTTP状态代码丰富的应用语义,那么你将错失提高重用性、增强互操作性和提升松耦合性的机会。

如果这些所谓的RESTful应用必须通过响应实体才能给出错误信息,那么SOAP就是这样的了,它就能够满足了。

2. 3 资源的表述

上面提到,客户端通过HTTP方法可以获取资源,是吧? 不,确切的说,客户端获取的只是资源的表述而已。 资源在外界的具体呈现,可以有多种表述(或成为表现、表示)形式,在客户端和服务端之间传送的也是资源的表述,而不是资源本身。 例如文本资源可以采用html、xml、json等格式,图片可以使用PNG或JPG展现出来。

资源的表述包括数据和描述数据的元数据,例如,HTTP头”Content-Type” 就是这样一个元数据属性。

那么客户端如何知道服务端提供哪种表述形式呢?

答案是可以通过HTTP内容协商,客户端可以通过Accept头请求一种特定格式的表述,服务端则通过Content-Type告诉客户端资源的表述形式。

以github为例,请求某组织资源的json格式的表述形式:

假如github也能够支持xml格式的表述格式,那么结果就是这样的:

下面我们来看一些实践上常见的设计:

在URI里边带上版本号

有些API在URI里边带上版本号,例如:

如果我们把版本号理解成资源的不同表述形式的话,就应该只是用一个URL,并通过Accept头部来区分,还是以github为例,它的Accept的完整格式是:application/vnd.github[.version].param[+json]

对于v3版本的话,就是Accept: application/vnd.github.v3。对于上面的例子,同理可以使用使用下面的头部:

  • Accept: vnd.example-com.foo+json; version=1.0
  • Accept: vnd.example-com.foo+json; version=1.2
  • Accept: vnd.example-com.foo+json; version=2.0

使用URI后缀来区分表述格式

像rails框架,就支持使用/users.xml或/users.json来区分不同的格式。 这样的方式对于客户端来说,无疑是更为直观,但混淆了资源的名称和资源的表述形式。 我个人认为,还是应该优先使用内容协商来区分表述格式。

如何处理不支持的表述格式

当服务器不支持所请求的表述格式,那么应该怎么办?若服务器不支持,它应该返回一个HTTP 406响应,表示拒绝处理该请求。下面以github为例,展示了一个请求XML表述资源的结果:

2. 4 资源的链接

我们知道REST是使用标准的HTTP方法来操作资源的,但仅仅因此就理解成带CURD的Web数据库架构就太过于简单了。

这种反模式忽略了一个核心概念:”超媒体即应用状态引擎(hypermedia as the engine of application state)”。 超媒体是什么?

当你浏览Web网页时,从一个连接跳到一个页面,再从另一个连接跳到另外一个页面,就是利用了超媒体的概念:把一个个把资源链接起来.

要达到这个目的,就要求在表述格式里边加入链接来引导客户端。在《RESTful Web Services》一书中,作者把这种具有链接的特性成为连通性。下面我们具体来看一些例子。

下面展示的是github获取某个组织下的项目列表的请求,可以看到在响应头里边增加Link头告诉客户端怎么访问下一页和最后一页的记录。 而在响应体里边,用url来链接项目所有者和项目地址。

又例如下面这个例子,创建订单后通过链接引导客户端如何去付款。

上面的例子展示了如何使用超媒体来增强资源的连通性。很多人在设计RESTful架构时,使用很多时间来寻找漂亮的URI,而忽略了超媒体。所以,应该多花一些时间来给资源的表述提供链接,而不是专注于”资源的CRUD”。

2. 5 状态的转移

有了上面的铺垫,再讨论REST里边的状态转移就会很容易理解了。

不过,我们先来讨论一下REST原则中的无状态通信原则。初看一下,好像自相矛盾了,既然无状态,何来状态转移一说?

其实,这里说的无状态通信原则,并不是说客户端应用不能有状态,而是指服务端不应该保存客户端状态。

2. 5.1 应用状态与资源状态

实际上,状态应该区分应用状态和资源状态,客户端负责维护应用状态,而服务端维护资源状态。

客户端与服务端的交互必须是无状态的,并在每一次请求中包含处理该请求所需的一切信息。

服务端不需要在请求间保留应用状态,只有在接受到实际请求的时候,服务端才会关注应用状态。

这种无状态通信原则,使得服务端和中介能够理解独立的请求和响应。

在多次请求中,同一客户端也不再需要依赖于同一服务器,方便实现高可扩展和高可用性的服务端。

但有时候我们会做出违反无状态通信原则的设计,例如利用Cookie跟踪某个服务端会话状态,常见的像J2EE里边的JSESSIONID。

这意味着,浏览器随各次请求发出去的Cookie是被用于构建会话状态的。

当然,如果Cookie保存的是一些服务器不依赖于会话状态即可验证的信息(比如认证令牌),这样的Cookie也是符合REST原则的。

2. 5.2 应用状态的转移

状态转移到这里已经很好理解了, “会话”状态不是作为资源状态保存在服务端的,而是被客户端作为应用状态进行跟踪的。客户端应用状态在服务端提供的超媒体的指引下发生变迁。服务端通过超媒体告诉客户端当前状态有哪些后续状态可以进入。

这些类似”下一页”之类的链接起的就是这种推进状态的作用——指引你如何从当前状态进入下一个可能的状态。

RESTful API 设计指南

 

网络应用程序,分为前端和后端两个部分。当前的发展趋势,就是前端设备层出不穷(手机、平板、桌面电脑、其他专用设备……)。

因此,必须有一种统一的机制,方便不同的前端设备与后端进行通信。这导致API构架的流行,甚至出现“API First”的设计思想。RESTful API是目前比较成熟的一套互联网应用程序的API设计理论。我以前写过一篇《理解RESTful架构》,探讨如何理解这个概念。

今天,我将介绍RESTful API的设计细节,探讨如何设计一套合理、好用的API。我的主要参考了两篇文章(12)。

RESTful API

一、协议

API与用户的通信协议,总是使用HTTPs协议

二、域名

应该尽量将API部署在专用域名之下。


https://api.example.com

如果确定API很简单,不会有进一步扩展,可以考虑放在主域名下。


https://example.org/api/

三、版本(Versioning)

应该将API的版本号放入URL。


https://api.example.com/v1/

另一种做法是,将版本号放在HTTP头信息中,但不如放入URL方便和直观。Github采用这种做法。

四、路径(Endpoint)

路径又称”终点”(endpoint),表示API的具体网址。

在RESTful架构中,每个网址代表一种资源(resource),所以网址中不能有动词,只能有名词,而且所用的名词往往与数据库的表格名对应。一般来说,数据库中的表都是同种记录的”集合”(collection),所以API中的名词也应该使用复数。

举例来说,有一个API提供动物园(zoo)的信息,还包括各种动物和雇员的信息,则它的路径应该设计成下面这样。

五、HTTP动词

对于资源的具体操作类型,由HTTP动词表示。

常用的HTTP动词有下面五个(括号里是对应的SQL命令)。

  • GET(SELECT):从服务器取出资源(一项或多项)。
  • POST(CREATE):在服务器新建一个资源。
  • PUT(UPDATE):在服务器更新资源(客户端提供改变后的完整资源)。
  • PATCH(UPDATE):在服务器更新资源(客户端提供改变的属性)。
  • DELETE(DELETE):从服务器删除资源。

还有两个不常用的HTTP动词。

  • HEAD:获取资源的元数据。
  • OPTIONS:获取信息,关于资源的哪些属性是客户端可以改变的。

下面是一些例子。

  • GET /zoos:列出所有动物园
  • POST /zoos:新建一个动物园
  • GET /zoos/ID:获取某个指定动物园的信息
  • PUT /zoos/ID:更新某个指定动物园的信息(提供该动物园的全部信息)
  • PATCH /zoos/ID:更新某个指定动物园的信息(提供该动物园的部分信息)
  • DELETE /zoos/ID:删除某个动物园
  • GET /zoos/ID/animals:列出某个指定动物园的所有动物
  • DELETE /zoos/ID/animals/ID:删除某个指定动物园的指定动物

六、过滤信息(Filtering)

如果记录数量很多,服务器不可能都将它们返回给用户。API应该提供参数,过滤返回结果。

下面是一些常见的参数。

  • ?limit=10:指定返回记录的数量
  • ?offset=10:指定返回记录的开始位置。
  • ?page=2&per_page=100:指定第几页,以及每页的记录数。
  • ?sortby=name&order=asc:指定返回结果按照哪个属性排序,以及排序顺序。
  • ?animal_type_id=1:指定筛选条件

参数的设计允许存在冗余,即允许API路径和URL参数偶尔有重复。比如,GET /zoo/ID/animals 与 GET /animals?zoo_id=ID 的含义是相同的。

七、状态码(Status Codes)

服务器向用户返回的状态码和提示信息,常见的有以下一些(方括号中是该状态码对应的HTTP动词)。

  • 200 OK – [GET]:服务器成功返回用户请求的数据,该操作是幂等的(Idempotent)。
  • 201 CREATED – [POST/PUT/PATCH]:用户新建或修改数据成功。
  • 202 Accepted – [*]:表示一个请求已经进入后台排队(异步任务)
  • 204 NO CONTENT – [DELETE]:用户删除数据成功。
  • 400 INVALID REQUEST – [POST/PUT/PATCH]:用户发出的请求有错误,服务器没有进行新建或修改数据的操作,该操作是幂等的。
  • 401 Unauthorized – [*]:表示用户没有权限(令牌、用户名、密码错误)。
  • 403 Forbidden – [*] 表示用户得到授权(与401错误相对),但是访问是被禁止的。
  • 404 NOT FOUND – [*]:用户发出的请求针对的是不存在的记录,服务器没有进行操作,该操作是幂等的。
  • 406 Not Acceptable – [GET]:用户请求的格式不可得(比如用户请求JSON格式,但是只有XML格式)。
  • 410 Gone -[GET]:用户请求的资源被永久删除,且不会再得到的。
  • 422 Unprocesable entity – [POST/PUT/PATCH] 当创建一个对象时,发生一个验证错误。
  • 500 INTERNAL SERVER ERROR – [*]:服务器发生错误,用户将无法判断发出的请求是否成功。

状态码的完全列表参见这里

八、错误处理(Error handling)

如果状态码是4xx,就应该向用户返回出错信息。一般来说,返回的信息中将error作为键名,出错信息作为键值即可。


{
    error: "Invalid API key"
}

九、返回结果

针对不同操作,服务器向用户返回的结果应该符合以下规范。

  • GET /collection:返回资源对象的列表(数组)
  • GET /collection/resource:返回单个资源对象
  • POST /collection:返回新生成的资源对象
  • PUT /collection/resource:返回完整的资源对象
  • PATCH /collection/resource:返回完整的资源对象
  • DELETE /collection/resource:返回一个空文档

十、Hypermedia API

RESTful API最好做到Hypermedia,即返回结果中提供链接,连向其他API方法,使得用户不查文档,也知道下一步应该做什么。

比如,当用户向api.example.com的根目录发出请求,会得到这样一个文档。


{"link": {
  "rel":   "collection https://www.example.com/zoos",
  "href":  "https://api.example.com/zoos",
  "title": "List of zoos",
  "type":  "application/vnd.yourformat+json"
}}

上面代码表示,文档中有一个link属性,用户读取这个属性就知道下一步该调用什么API了。rel表示这个API与当前网址的关系(collection关系,并给出该collection的网址),href表示API的路径,title表示API的标题,type表示返回类型。

Hypermedia API的设计被称为HATEOAS。Github的API就是这种设计,访问api.github.com会得到一个所有可用API的网址列表。


{
  "current_user_url": "https://api.github.com/user",
  "authorizations_url": "https://api.github.com/authorizations",
  // ...
}

从上面可以看到,如果想获取当前用户的信息,应该去访问api.github.com/user,然后就得到了下面结果。


{
  "message": "Requires authentication",
  "documentation_url": "https://developer.github.com/v3"
}

上面代码表示,服务器给出了提示信息,以及文档的网址。

十一、其他

(1)API的身份认证应该使用OAuth 2.0框架。

(2)服务器返回的数据格式,应该尽量使用JSON,避免使用XML。

总结

符合REST设计标准的API,即RESTful API。REST架构设计,遵循的各项标准和准则,就是HTTP协议的表现,换句话说,HTTP协议就是属于REST架构的设计模式。比如,无状态,请求-响应。。。

参考:
理解本身的REST架构风格
http://www.infoq.com/cn/articles/understanding-restful-style/

理解RESTful架构
http://www.ruanyifeng.com/blog/2011/09/restful.html

Restful API设计指南
http://www.ruanyifeng.com/blog/2014/05/restful_api.html

REST与RESTFul API最佳实践

http://www.imooc.com/article/17650

发表在 码农日常 | 标签为 | 留下评论

对RESTful API的个人看法

http://blog.csdn.net/enweitech/article/details/79208321

 

什么是REST?

可以总结为一句话:REST是所有Web应用都应该遵守的架构设计指导原则。
Representational State Transfer,翻译是”表现层状态转化”。
面向资源是REST最明显的特征,对于同一个资源的一组不同的操作。资源是服务器上一个可命名的抽象概念,资源是以名词为核心来组织的,首先关注的是名词。REST要求,必须通过统一的接口来对资源执行各种操作。对于每个资源只能执行一组有限的操作。(7个HTTP方法:GET/POST/PUT/DELETE/PATCH/HEAD/OPTIONS)

什么是RESTful API?

符合REST架构设计的API。

1. 什么是REST

 

REST全称是Representational State Transfer,中文意思是表述(编者注:通常译为表征)性状态转移。 它首次出现在2000年Roy Fielding的博士论文中,Roy Fielding是HTTP规范的主要编写者之一。 他在论文中提到:”我这篇文章的写作目的,就是想在符合架构原理的前提下,理解和评估以网络为基础的应用软件的架构设计,得到一个功能强、性能好、适宜通信的架构。REST指的是一组架构约束条件和原则。” 如果一个架构符合REST的约束条件和原则,我们就称它为RESTful架构。

REST本身并没有创造新的技术、组件或服务,而隐藏在RESTful背后的理念就是使用Web的现有特征和能力, 更好地使用现有Web标准中的一些准则和约束。虽然REST本身受Web技术的影响很深, 但是理论上REST架构风格并不是绑定在HTTP上,只不过目前HTTP是唯一与REST相关的实例。 所以我们这里描述的REST也是通过HTTP实现的REST。

2. 理解RESTful

要理解RESTful架构,需要理解Representational State Transfer这个词组到底是什么意思,它的每一个词都有些什么涵义。

下面我们结合REST原则,围绕资源展开讨论,从资源的定义、获取、表述、关联、状态变迁等角度,列举一些关键概念并加以解释。

  • 资源与URI
  • 统一资源接口
  • 资源的表述
  • 资源的链接
  • 状态的转移

2. 1 资源与URI

REST全称是表述性状态转移,那究竟指的是什么的表述? 其实指的就是资源。任何事物,只要有被引用到的必要,它就是一个资源。资源可以是实体(例如手机号码),也可以只是一个抽象概念(例如价值) 。下面是一些资源的例子:

  • 某用户的手机号码
  • 某用户的个人信息
  • 最多用户订购的GPRS套餐
  • 两个产品之间的依赖关系
  • 某用户可以办理的优惠套餐
  • 某手机号码的潜在价值

要让一个资源可以被识别,需要有个唯一标识,在Web中这个唯一标识就是URI(Uniform Resource Identifier)。

URI既可以看成是资源的地址,也可以看成是资源的名称。如果某些信息没有使用URI来表示,那它就不能算是一个资源, 只能算是资源的一些信息而已。URI的设计应该遵循可寻址性原则,具有自描述性,需要在形式上给人以直觉上的关联。这里以github网站为例,给出一些还算不错的URI:

下面让我们来看看URI设计上的一些技巧:

  • 使用_或-来让URI可读性更好

曾经Web上的URI都是冰冷的数字或者无意义的字符串,但现在越来越多的网站使用_或-来分隔一些单词,让URI看上去更为人性化。 例如国内比较出名的开源中国社区,它上面的新闻地址就采用这种风格, 如http://www.oschina.net/news/38119/oschina-translate-reward-plan。

  • 使用/来表示资源的层级关系

例如上述/git/git/commit/e3af72cdafab5993d18fae056f87e1d675913d08就表示了一个多级的资源, 指的是git用户的git项目的某次提交记录,又例如/orders/2012/10可以用来表示2012年10月的订单记录。

  • 使用?用来过滤资源

很多人只是把?简单的当做是参数的传递,很容易造成URI过于复杂、难以理解。可以把?用于对资源的过滤, 例如/git/git/pulls用来表示git项目的所有推入请求,而/pulls?state=closed用来表示git项目中已经关闭的推入请求, 这种URL通常对应的是一些特定条件的查询结果或算法运算结果。

  • ,或;可以用来表示同级资源的关系

有时候我们需要表示同级资源的关系时,可以使用,或;来进行分割。例如哪天github可以比较某个文件在随意两次提交记录之间的差异,或许可以使用/git/git /block-sha1/sha1.h/compare/e3af72cdafab5993d18fae056f87e1d675913d08;bd63e61bdf38e872d5215c07b264dcc16e4febca作为URI。 不过,现在github是使用…来做这个事情的,例如/git/git/compare/master…next。

2. 2 统一资源接口

RESTful架构应该遵循统一接口原则,统一接口包含了一组受限的预定义的操作,不论什么样的资源,都是通过使用相同的接口进行资源的访问。接口应该使用标准的HTTP方法如GET,PUT和POST,并遵循这些方法的语义。

如果按照HTTP方法的语义来暴露资源,那么接口将会拥有安全性和幂等性的特性,例如GET和HEAD请求都是安全的, 无论请求多少次,都不会改变服务器状态。而GET、HEAD、PUT和DELETE请求都是幂等的,无论对资源操作多少次, 结果总是一样的,后面的请求并不会产生比第一次更多的影响。

下面列出了GET,DELETE,PUT和POST的典型用法:

GET

  • 安全且幂等
  • 获取表示
  • 变更时获取表示(缓存)
  • 200(OK) – 表示已在响应中发出
  • 204(无内容) – 资源有空表示
  • 301(Moved Permanently) – 资源的URI已被更新
  • 303(See Other) – 其他(如,负载均衡)
  • 304(not modified)- 资源未更改(缓存)
  • 400 (bad request)- 指代坏请求(如,参数错误)
  • 404 (not found)- 资源不存在
  • 406 (not acceptable)- 服务端不支持所需表示
  • 500 (internal server error)- 通用错误响应
  • 503 (Service Unavailable)- 服务端当前无法处理请求

POST

  • 不安全且不幂等
  • 使用服务端管理的(自动产生)的实例号创建资源
  • 创建子资源
  • 部分更新资源
  • 如果没有被修改,则不过更新资源(乐观锁)
  • 200(OK)- 如果现有资源已被更改
  • 201(created)- 如果新资源被创建
  • 202(accepted)- 已接受处理请求但尚未完成(异步处理)
  • 301(Moved Permanently)- 资源的URI被更新
  • 303(See Other)- 其他(如,负载均衡)
  • 400(bad request)- 指代坏请求
  • 404 (not found)- 资源不存在
  • 406 (not acceptable)- 服务端不支持所需表示
  • 409 (conflict)- 通用冲突
  • 412 (Precondition Failed)- 前置条件失败(如执行条件更新时的冲突)
  • 415 (unsupported media type)- 接受到的表示不受支持
  • 500 (internal server error)- 通用错误响应
  • 503 (Service Unavailable)- 服务当前无法处理请求

PUT

  • 不安全但幂等
  • 用客户端管理的实例号创建一个资源
  • 通过替换的方式更新资源
  • 如果未被修改,则更新资源(乐观锁)
  • 200 (OK)- 如果已存在资源被更改
  • 201 (created)- 如果新资源被创建
  • 301(Moved Permanently)- 资源的URI已更改
  • 303 (See Other)- 其他(如,负载均衡)
  • 400 (bad request)- 指代坏请求
  • 404 (not found)- 资源不存在
  • 406 (not acceptable)- 服务端不支持所需表示
  • 409 (conflict)- 通用冲突
  • 412 (Precondition Failed)- 前置条件失败(如执行条件更新时的冲突)
  • 415 (unsupported media type)- 接受到的表示不受支持
  • 500 (internal server error)- 通用错误响应
  • 503 (Service Unavailable)- 服务当前无法处理请求

DELETE

  • 不安全但幂等
  • 删除资源
  • 200 (OK)- 资源已被删除
  • 301 (Moved Permanently)- 资源的URI已更改
  • 303 (See Other)- 其他,如负载均衡
  • 400 (bad request)- 指代坏请求
  • 404 (not found)- 资源不存在
  • 409 (conflict)- 通用冲突
  • 500 (internal server error)- 通用错误响应
  • 503 (Service Unavailable)- 服务端当前无法处理请求

下面我们来看一些实践中常见的问题:

  • POST和PUT用于创建资源时有什么区别?

POST和PUT在创建资源的区别在于,所创建的资源的名称(URI)是否由客户端决定。 例如为我的博文增加一个java的分类,生成的路径就是分类名/categories/java,那么就可以采用PUT方法。不过很多人直接把POST、GET、PUT、DELETE直接对应上CRUD,例如在一个典型的rails实现的RESTful应用中就是这么做的。

我认为,这是因为rails默认使用服务端生成的ID作为URI的缘故,而不少人就是通过rails实践REST的,所以很容易造成这种误解。

  • 客户端不一定都支持这些HTTP方法吧?

的确有这种情况,特别是一些比较古老的基于浏览器的客户端,只能支持GET和POST两种方法。

在实践上,客户端和服务端都可能需要做一些妥协。例如rails框架就支持通过隐藏参数_method=DELETE来传递真实的请求方法, 而像Backbone这样的客户端MVC框架则允许传递_method传输和设置X-HTTP-Method-Override头来规避这个问题。

  • 统一接口是否意味着不能扩展带特殊语义的方法?

统一接口并不阻止你扩展方法,只要方法对资源的操作有着具体的、可识别的语义即可,并能够保持整个接口的统一性。

像WebDAV就对HTTP方法进行了扩展,增加了LOCK、UPLOCK等方法。而github的API则支持使用PATCH方法来进行issue的更新,例如:

PATCH /repos/:owner/:repo/issues/:number

不过,需要注意的是,像PATCH这种不是HTTP标准方法的,服务端需要考虑客户端是否能够支持的问题。

  • 统一资源接口对URI有什么指导意义?

统一资源接口要求使用标准的HTTP方法对资源进行操作,所以URI只应该来表示资源的名称,而不应该包括资源的操作。

通俗来说,URI不应该使用动作来描述。例如,下面是一些不符合统一接口要求的URI:

  • GET /getUser/1
  • POST /createUser
  • PUT /updateUser/1
  • DELETE /deleteUser/1

如果GET请求增加计数器,这是否违反安全性?

安全性不代表请求不产生副作用,例如像很多API开发平台,都对请求流量做限制。像github,就会限制没有认证的请求每小时只能请求60次。

但客户端不是为了追求副作用而发出这些GET或HEAD请求的,产生副作用是服务端”自作主张”的。

另外,服务端在设计时,也不应该让副作用太大,因为客户端认为这些请求是不会产生副作用的。

  • 直接忽视缓存可取吗?

即使你按各个动词的原本意图来使用它们,你仍可以轻易禁止缓存机制。 最简单的做法就是在你的HTTP响应里增加这样一个报头: Cache-control: no-cache。 但是,同时你也对失去了高效的缓存与再验证的支持(使用Etag等机制)。

对于客户端来说,在为一个REST式服务实现程序客户端时,也应该充分利用现有的缓存机制,以免每次都重新获取表示。

  • 响应代码的处理有必要吗?

HTTP的响应代码可用于应付不同场合,正确使用这些状态代码意味着客户端与服务器可以在一个具备较丰富语义的层次上进行沟通。

例如,201(”Created”)响应代码表明已经创建了一个新的资源,其URI在Location响应报头里。

假如你不利用HTTP状态代码丰富的应用语义,那么你将错失提高重用性、增强互操作性和提升松耦合性的机会。

如果这些所谓的RESTful应用必须通过响应实体才能给出错误信息,那么SOAP就是这样的了,它就能够满足了。

2. 3 资源的表述

上面提到,客户端通过HTTP方法可以获取资源,是吧? 不,确切的说,客户端获取的只是资源的表述而已。 资源在外界的具体呈现,可以有多种表述(或成为表现、表示)形式,在客户端和服务端之间传送的也是资源的表述,而不是资源本身。 例如文本资源可以采用html、xml、json等格式,图片可以使用PNG或JPG展现出来。

资源的表述包括数据和描述数据的元数据,例如,HTTP头”Content-Type” 就是这样一个元数据属性。

那么客户端如何知道服务端提供哪种表述形式呢?

答案是可以通过HTTP内容协商,客户端可以通过Accept头请求一种特定格式的表述,服务端则通过Content-Type告诉客户端资源的表述形式。

以github为例,请求某组织资源的json格式的表述形式:

假如github也能够支持xml格式的表述格式,那么结果就是这样的:

下面我们来看一些实践上常见的设计:

在URI里边带上版本号

有些API在URI里边带上版本号,例如:

如果我们把版本号理解成资源的不同表述形式的话,就应该只是用一个URL,并通过Accept头部来区分,还是以github为例,它的Accept的完整格式是:application/vnd.github[.version].param[+json]

对于v3版本的话,就是Accept: application/vnd.github.v3。对于上面的例子,同理可以使用使用下面的头部:

  • Accept: vnd.example-com.foo+json; version=1.0
  • Accept: vnd.example-com.foo+json; version=1.2
  • Accept: vnd.example-com.foo+json; version=2.0

使用URI后缀来区分表述格式

像rails框架,就支持使用/users.xml或/users.json来区分不同的格式。 这样的方式对于客户端来说,无疑是更为直观,但混淆了资源的名称和资源的表述形式。 我个人认为,还是应该优先使用内容协商来区分表述格式。

如何处理不支持的表述格式

当服务器不支持所请求的表述格式,那么应该怎么办?若服务器不支持,它应该返回一个HTTP 406响应,表示拒绝处理该请求。下面以github为例,展示了一个请求XML表述资源的结果:

2. 4 资源的链接

我们知道REST是使用标准的HTTP方法来操作资源的,但仅仅因此就理解成带CURD的Web数据库架构就太过于简单了。

这种反模式忽略了一个核心概念:”超媒体即应用状态引擎(hypermedia as the engine of application state)”。 超媒体是什么?

当你浏览Web网页时,从一个连接跳到一个页面,再从另一个连接跳到另外一个页面,就是利用了超媒体的概念:把一个个把资源链接起来.

要达到这个目的,就要求在表述格式里边加入链接来引导客户端。在《RESTful Web Services》一书中,作者把这种具有链接的特性成为连通性。下面我们具体来看一些例子。

下面展示的是github获取某个组织下的项目列表的请求,可以看到在响应头里边增加Link头告诉客户端怎么访问下一页和最后一页的记录。 而在响应体里边,用url来链接项目所有者和项目地址。

又例如下面这个例子,创建订单后通过链接引导客户端如何去付款。

上面的例子展示了如何使用超媒体来增强资源的连通性。很多人在设计RESTful架构时,使用很多时间来寻找漂亮的URI,而忽略了超媒体。所以,应该多花一些时间来给资源的表述提供链接,而不是专注于”资源的CRUD”。

2. 5 状态的转移

有了上面的铺垫,再讨论REST里边的状态转移就会很容易理解了。

不过,我们先来讨论一下REST原则中的无状态通信原则。初看一下,好像自相矛盾了,既然无状态,何来状态转移一说?

其实,这里说的无状态通信原则,并不是说客户端应用不能有状态,而是指服务端不应该保存客户端状态。

2. 5.1 应用状态与资源状态

实际上,状态应该区分应用状态和资源状态,客户端负责维护应用状态,而服务端维护资源状态。

客户端与服务端的交互必须是无状态的,并在每一次请求中包含处理该请求所需的一切信息。

服务端不需要在请求间保留应用状态,只有在接受到实际请求的时候,服务端才会关注应用状态。

这种无状态通信原则,使得服务端和中介能够理解独立的请求和响应。

在多次请求中,同一客户端也不再需要依赖于同一服务器,方便实现高可扩展和高可用性的服务端。

但有时候我们会做出违反无状态通信原则的设计,例如利用Cookie跟踪某个服务端会话状态,常见的像J2EE里边的JSESSIONID。

这意味着,浏览器随各次请求发出去的Cookie是被用于构建会话状态的。

当然,如果Cookie保存的是一些服务器不依赖于会话状态即可验证的信息(比如认证令牌),这样的Cookie也是符合REST原则的。

2. 5.2 应用状态的转移

状态转移到这里已经很好理解了, “会话”状态不是作为资源状态保存在服务端的,而是被客户端作为应用状态进行跟踪的。客户端应用状态在服务端提供的超媒体的指引下发生变迁。服务端通过超媒体告诉客户端当前状态有哪些后续状态可以进入。

这些类似”下一页”之类的链接起的就是这种推进状态的作用——指引你如何从当前状态进入下一个可能的状态。

RESTful API 设计指南

 

网络应用程序,分为前端和后端两个部分。当前的发展趋势,就是前端设备层出不穷(手机、平板、桌面电脑、其他专用设备……)。

因此,必须有一种统一的机制,方便不同的前端设备与后端进行通信。这导致API构架的流行,甚至出现“API First”的设计思想。RESTful API是目前比较成熟的一套互联网应用程序的API设计理论。我以前写过一篇《理解RESTful架构》,探讨如何理解这个概念。

今天,我将介绍RESTful API的设计细节,探讨如何设计一套合理、好用的API。我的主要参考了两篇文章(12)。

RESTful API

一、协议

API与用户的通信协议,总是使用HTTPs协议

二、域名

应该尽量将API部署在专用域名之下。


https://api.example.com

如果确定API很简单,不会有进一步扩展,可以考虑放在主域名下。


https://example.org/api/

三、版本(Versioning)

应该将API的版本号放入URL。


https://api.example.com/v1/

另一种做法是,将版本号放在HTTP头信息中,但不如放入URL方便和直观。Github采用这种做法。

四、路径(Endpoint)

路径又称”终点”(endpoint),表示API的具体网址。

在RESTful架构中,每个网址代表一种资源(resource),所以网址中不能有动词,只能有名词,而且所用的名词往往与数据库的表格名对应。一般来说,数据库中的表都是同种记录的”集合”(collection),所以API中的名词也应该使用复数。

举例来说,有一个API提供动物园(zoo)的信息,还包括各种动物和雇员的信息,则它的路径应该设计成下面这样。

五、HTTP动词

对于资源的具体操作类型,由HTTP动词表示。

常用的HTTP动词有下面五个(括号里是对应的SQL命令)。

  • GET(SELECT):从服务器取出资源(一项或多项)。
  • POST(CREATE):在服务器新建一个资源。
  • PUT(UPDATE):在服务器更新资源(客户端提供改变后的完整资源)。
  • PATCH(UPDATE):在服务器更新资源(客户端提供改变的属性)。
  • DELETE(DELETE):从服务器删除资源。

还有两个不常用的HTTP动词。

  • HEAD:获取资源的元数据。
  • OPTIONS:获取信息,关于资源的哪些属性是客户端可以改变的。

下面是一些例子。

  • GET /zoos:列出所有动物园
  • POST /zoos:新建一个动物园
  • GET /zoos/ID:获取某个指定动物园的信息
  • PUT /zoos/ID:更新某个指定动物园的信息(提供该动物园的全部信息)
  • PATCH /zoos/ID:更新某个指定动物园的信息(提供该动物园的部分信息)
  • DELETE /zoos/ID:删除某个动物园
  • GET /zoos/ID/animals:列出某个指定动物园的所有动物
  • DELETE /zoos/ID/animals/ID:删除某个指定动物园的指定动物

六、过滤信息(Filtering)

如果记录数量很多,服务器不可能都将它们返回给用户。API应该提供参数,过滤返回结果。

下面是一些常见的参数。

  • ?limit=10:指定返回记录的数量
  • ?offset=10:指定返回记录的开始位置。
  • ?page=2&per_page=100:指定第几页,以及每页的记录数。
  • ?sortby=name&order=asc:指定返回结果按照哪个属性排序,以及排序顺序。
  • ?animal_type_id=1:指定筛选条件

参数的设计允许存在冗余,即允许API路径和URL参数偶尔有重复。比如,GET /zoo/ID/animals 与 GET /animals?zoo_id=ID 的含义是相同的。

七、状态码(Status Codes)

服务器向用户返回的状态码和提示信息,常见的有以下一些(方括号中是该状态码对应的HTTP动词)。

  • 200 OK – [GET]:服务器成功返回用户请求的数据,该操作是幂等的(Idempotent)。
  • 201 CREATED – [POST/PUT/PATCH]:用户新建或修改数据成功。
  • 202 Accepted – [*]:表示一个请求已经进入后台排队(异步任务)
  • 204 NO CONTENT – [DELETE]:用户删除数据成功。
  • 400 INVALID REQUEST – [POST/PUT/PATCH]:用户发出的请求有错误,服务器没有进行新建或修改数据的操作,该操作是幂等的。
  • 401 Unauthorized – [*]:表示用户没有权限(令牌、用户名、密码错误)。
  • 403 Forbidden – [*] 表示用户得到授权(与401错误相对),但是访问是被禁止的。
  • 404 NOT FOUND – [*]:用户发出的请求针对的是不存在的记录,服务器没有进行操作,该操作是幂等的。
  • 406 Not Acceptable – [GET]:用户请求的格式不可得(比如用户请求JSON格式,但是只有XML格式)。
  • 410 Gone -[GET]:用户请求的资源被永久删除,且不会再得到的。
  • 422 Unprocesable entity – [POST/PUT/PATCH] 当创建一个对象时,发生一个验证错误。
  • 500 INTERNAL SERVER ERROR – [*]:服务器发生错误,用户将无法判断发出的请求是否成功。

状态码的完全列表参见这里

八、错误处理(Error handling)

如果状态码是4xx,就应该向用户返回出错信息。一般来说,返回的信息中将error作为键名,出错信息作为键值即可。


{
    error: "Invalid API key"
}

九、返回结果

针对不同操作,服务器向用户返回的结果应该符合以下规范。

  • GET /collection:返回资源对象的列表(数组)
  • GET /collection/resource:返回单个资源对象
  • POST /collection:返回新生成的资源对象
  • PUT /collection/resource:返回完整的资源对象
  • PATCH /collection/resource:返回完整的资源对象
  • DELETE /collection/resource:返回一个空文档

十、Hypermedia API

RESTful API最好做到Hypermedia,即返回结果中提供链接,连向其他API方法,使得用户不查文档,也知道下一步应该做什么。

比如,当用户向api.example.com的根目录发出请求,会得到这样一个文档。


{"link": {
  "rel":   "collection https://www.example.com/zoos",
  "href":  "https://api.example.com/zoos",
  "title": "List of zoos",
  "type":  "application/vnd.yourformat+json"
}}

上面代码表示,文档中有一个link属性,用户读取这个属性就知道下一步该调用什么API了。rel表示这个API与当前网址的关系(collection关系,并给出该collection的网址),href表示API的路径,title表示API的标题,type表示返回类型。

Hypermedia API的设计被称为HATEOAS。Github的API就是这种设计,访问api.github.com会得到一个所有可用API的网址列表。


{
  "current_user_url": "https://api.github.com/user",
  "authorizations_url": "https://api.github.com/authorizations",
  // ...
}

从上面可以看到,如果想获取当前用户的信息,应该去访问api.github.com/user,然后就得到了下面结果。


{
  "message": "Requires authentication",
  "documentation_url": "https://developer.github.com/v3"
}

上面代码表示,服务器给出了提示信息,以及文档的网址。

十一、其他

(1)API的身份认证应该使用OAuth 2.0框架。

(2)服务器返回的数据格式,应该尽量使用JSON,避免使用XML。

总结

符合REST设计标准的API,即RESTful API。REST架构设计,遵循的各项标准和准则,就是HTTP协议的表现,换句话说,HTTP协议就是属于REST架构的设计模式。比如,无状态,请求-响应。。。

参考:
理解本身的REST架构风格
http://www.infoq.com/cn/articles/understanding-restful-style/

理解RESTful架构
http://www.ruanyifeng.com/blog/2011/09/restful.html

Restful API设计指南
http://www.ruanyifeng.com/blog/2014/05/restful_api.html

REST与RESTFul API最佳实践

http://www.imooc.com/article/17650

发表在 码农日常 | 标签为 | 留下评论

/dev/mapper/VolGroup00-root 满了关于inodes占用100%的问题及解决方法

http://blog.csdn.net/enweitech/article/details/53927768

现象:
[root@localhost ~]# df -h
Filesystem                    Size  Used Avail Use% Mounted on
/dev/mapper/VolGroup-lv_root   50G   48G     0 100% /
tmpfs                         1.7G   80K  1.7G   1% /dev/shm
/dev/sda1                     485M   40M  420M   9% /boot
/dev/mapper/VolGroup-lv_home  848G  2.3G  803G   1% /home

解决方法:

1、查找占空间大,且没用的文件或文件夹,删除掉。

find / -size +100M -exec ls -lh {} \;

2、对该分区扩容,方法如下:

目标:将VolGroup-lv_home缩小到20G,并将剩余的空间添加给VolGroup-lv_root
1.首先查看磁盘使用情况
[root@localhost ~]# df -h
文件系统 容量  已用 可用  已用% 挂载点
Filesystem             Size  Used Avail Use% Mounted on
/dev/mapper/VolGroup-lv_root 154G  7.9G  139G   6% /
tmpfs                 1.9G  100K  1.9G   1% /dev/shm
/dev/sda1             485M   69M  391M  15% /boot
/dev/mapper/VolGroup-lv_home 299G  984M  283G   1% /home
2、卸载/home
[root@localhost ~]# umount /home
umount /home 如果提示无法卸载,则是有进程占用/home,使用如下命令来终止占用进程:
[root@localhost ~]# fuser -km /home
3、调整分区大小
[root@localhost ~]# resize2fs -p /dev/mapper/VolGroup-lv_home 20G
如果提示运行“e2fsck -f /dev/mapper/VolGroup-lv_home”,则执行相关命令:
[root@localhost ~]# e2fsck -f /dev/mapper/VolGroup-lv_home 然后重新执行命令:
[root@localhost ~]# resize2fs -p /dev/mapper/VolGroup-lv_home 20G
注:resize2fs 为重新设定磁盘大小,只是重新指定一下大小,并不对结果有影响,需要下面lvreduce的配合
4、挂载上/home,查看磁盘使用情况
[root@localhost ~]# mount /home
[root@localhost ~]# df -h
5、设置空闲空间
使用lvreduce指令用于减少LVM逻辑卷占用的空间大小。可能会删除逻辑卷上已有的数据,所以在操作前必须进行确认。记得输入 “y”
[root@localhost ~]# lvreduce -L 20G /dev/mapper/VolGroup-lv_home
注:lvreduce -L 20G的意思为设置当前文件系统为20G,如果lvreduce -l 20G是指从当前文件系统上减少20G
使用lvreduce减小逻辑卷的大小。注意:减小后的大小不能小于文件的大小,否则会丢失数据。
可以使用vgdisplay命令等查看一下可以操作的大小。也可以是用fdisk -l命令查看详细信息。
[root@localhost ~]# vgdisplay
注:vgdisplay为显示LVM卷组的元数据信息
6.把闲置空间挂在到根目录下
[root@localhost ~]# lvextend -L +283G /dev/mapper/VolGroup-lv_root
注:lvextend -L +283G为在文件系统上增加283G
[root@localhost ~]# resize2fs -p /dev/mapper/VolGroup-lv_root
7、检查调整结果
[root@localhost ~]# df -h
[场景]/dev/mapper/VolGroup00-LogVol00 是逻辑卷/ 根目录才是实际挂载的目录。根分区都塞满了,自己清理一些垃圾文件或者加硬盘在线扩容、主要看看/tmp /var目录下的一些临时文件和一些日志文件,选择些的进行清理给你个命令`看下哪个目录下东西大find / -size +10M -exec ls -lh {} \;

df -i

​for i in ./*; do echo $i; find $i | wc -l; done  查文件数量

今天nagios报警,一台服务器的disk满了,使用du -sh * 或 du -sh /* 查看目录的大小,查找占用空间大的目录/var/spool/clientmqueue….

然后我就想/var/spool/clientmqueue这个目录干嘛用的,纠结了半天,谷歌了下,原来/var/spool/clientmqueue是如果系统中有用户开启了cron,而cron中执行的程序有输出内容,输出内容会以邮件形式发给cron的用户,而sendmail没有启动所以就产生了这些文件。

服务器上确实有cron定时执行数十个脚本,而且都没有设置输出定向,日积月累的文件都被保存在/var/spool/clientmqueue目录下面乐 = =.

解决方法:在cron的自动执行语句后加上> /dev/null 2>&1例:4 3 * * * /usr/bin/w > /dev/null 2>&1这样就OK拉,就不会写到那个目录下了….

在这里说一点,/var/spool/clientmqueue目录文件太多,rm -rf *时候会提示:

“-bash: /bin/rm: Argument list too long“..意思是参数太长,rm 干不了。可以用ls | xargs rm -f这个命令将/var/spool/clientmqueue目录下所有文件删除

OK。清理完毕~

情况描述:今天我们邮件服务器收发不了邮件了,而且连接到服务器上开启服务都开不了,起始以为磁盘空间不足,df 看了一下

发现空间是足够的,然后df -i 查看了下inodes,发现根目录下的inodes值使用率为100%了

解决方法:通过以下脚本进行检查,查看到底哪个目录下面的文件最多:

for i in /*; do echo $i; find $i | wc -l; done(如果确定是某个目录下面,则/转换为该目录绝对路径,如/var/spool,则使用for i in /var/spool/*; do echo $i; find $i | wc -l; done)

最终发现/var/soppl目录最多。然后又进一步确定是/var/spool/amavisd/quarantine 目录下面有上百万个文件,机器已经无法正常显示了,后来百度查看了下这个目录是邮件服务器,处理垃圾邮件活病毒邮件隔离的,明白原因了,删除该目录下所有文件;使用xargs命令来删除数量比较多的文件:

ls | xargs -n 10 rm -rf

执行了大约10多小时之后,最终解决问题。

操作命令:

for i in /var/spool/*; do echo $i; find $i | wc -l; done

[root@L-AP-3-37 ~]# cd /var/spool/clientmqueue

[root@L-AP-3-37 clientmqueue]# ls | xargs rm -f

发表在 码农日常 | 标签为 | 留下评论

linux下find命令之-exec ll -sh {} \;

http://www.mamicode.com/info-detail-1278781.html

exec解释:

-exec  参数后面跟的是command命令,它的终止是以;为结束标志的,所以这句命令后面的分号是不可缺少的,考虑到各个系统中分号会有不同的意义,所以前面加反斜杠。

{}   花括号代表前面find查找出来的文件名。

使用find时,只要把想要的操作写在一个文件里,就可以用exec来配合find查找,很方便的。在有些操作系统中只允许-exec选项执行诸如l s或ls -l这样的命令。大多数用户使用这一选项是为了查找旧文件并删除它们。建议在真正执行rm命令删除文件之前,最好先用ls命令看一下,确认它们是所要删除的文件。 exec选项后面跟随着所要执行的命令或脚本,然后是一对儿{ },一个空格和一个\,最后是一个分号。为了使用exec选项,必须要同时使用print选项。如果验证一下find命令,会发现该命令只输出从当前路径起的相对路径及文件名。

实例1:ls -l命令放在find命令的-exec选项中

命令:

find . -type f -exec ls -l {} \;

输出:

[root@localhost test]# find . -type f -exec ls -l {} \;

-rw-r–r– 1 root root 127 10-28 16:51 ./log2014.log

-rw-r–r– 1 root root 0 10-28 14:47 ./test4/log3-2.log

-rw-r–r– 1 root root 0 10-28 14:47 ./test4/log3-3.log

-rw-r–r– 1 root root 0 10-28 14:47 ./test4/log3-1.log

-rw-r–r– 1 root root 33 10-28 16:54 ./log2013.log

-rw-r–r– 1 root root 302108 11-03 06:19 ./log2012.log

-rw-r–r– 1 root root 25 10-28 17:02 ./log.log

-rw-r–r– 1 root root 37 10-28 17:07 ./log.txt

-rw-r–r– 1 root root 0 10-28 14:47 ./test3/log3-2.log

-rw-r–r– 1 root root 0 10-28 14:47 ./test3/log3-3.log

-rw-r–r– 1 root root 0 10-28 14:47 ./test3/log3-1.log

[root@localhost test]#

说明:

上面的例子中,find命令匹配到了当前目录下的所有普通文件,并在-exec选项中使用ls -l命令将它们列出。

实例2:在目录中查找更改时间在n日以前的文件并删除它们

命令:

find . -type f -mtime +14 -exec rm {} \;

输出:

[root@localhost test]# ll

总计 328

-rw-r–r– 1 root root 302108 11-03 06:19 log2012.log

-rw-r–r– 1 root root     33 10-28 16:54 log2013.log

-rw-r–r– 1 root root    127 10-28 16:51 log2014.log

lrwxrwxrwx 1 root root      7 10-28 15:18 log_link.log -> log.log

-rw-r–r– 1 root root     25 10-28 17:02 log.log

-rw-r–r– 1 root root     37 10-28 17:07 log.txt

drwxr-xr-x 6 root root   4096 10-27 01:58 scf

drwxrwxrwx 2 root root   4096 10-28 14:47 test3

drwxrwxrwx 2 root root   4096 10-28 14:47 test4

[root@localhost test]# find . -type f -mtime +14 -exec rm {} \;

[root@localhost test]# ll

总计 312

-rw-r–r– 1 root root 302108 11-03 06:19 log2012.log

lrwxrwxrwx 1 root root      7 10-28 15:18 log_link.log -> log.log

drwxr-xr-x 6 root root   4096 10-27 01:58 scf

drwxrwxrwx 2 root root   4096 11-12 19:32 test3

drwxrwxrwx 2 root root   4096 11-12 19:32 test4

说明:

在shell中用任何方式删除文件之前,应当先查看相应的文件,一定要小心!当使用诸如mv或rm命令时,可以使用-exec选项的安全模式。它将在对每个匹配到的文件进行操作之前提示你。

实例3:在目录中查找更改时间在n日以前的文件并删除它们,在删除之前先给出提示

命令:

find . -name “*.log” -mtime +5 -ok rm {} \;

输出:

[root@localhost test]# ll

总计 312

-rw-r–r– 1 root root 302108 11-03 06:19 log2012.log

lrwxrwxrwx 1 root root      7 10-28 15:18 log_link.log -> log.log

drwxr-xr-x 6 root root   4096 10-27 01:58 scf

drwxrwxrwx 2 root root   4096 11-12 19:32 test3

drwxrwxrwx 2 root root   4096 11-12 19:32 test4

[root@localhost test]# find . -name “*.log” -mtime +5 -ok rm {} \;

< rm … ./log_link.log > ? y

< rm … ./log2012.log > ? n

[root@localhost test]# ll

总计 312

-rw-r–r– 1 root root 302108 11-03 06:19 log2012.log

drwxr-xr-x 6 root root   4096 10-27 01:58 scf

drwxrwxrwx 2 root root   4096 11-12 19:32 test3

drwxrwxrwx 2 root root   4096 11-12 19:32 test4

[root@localhost test]#

说明:

在上面的例子中, find命令在当前目录中查找所有文件名以.log结尾、更改时间在5日以上的文件,并删除它们,只不过在删除之前先给出提示。 按y键删除文件,按n键不删除。

 

实例4:-exec中使用grep命令

命令:

find /etc -name “passwd*” -exec grep “root” {} \;

输出:

[root@localhost test]# find /etc -name “passwd*” -exec grep “root” {} \;

root:x:0:0:root:/root:/bin/bash

root:x:0:0:root:/root:/bin/bash

[root@localhost test]#

说明:

任何形式的命令都可以在-exec选项中使用。  在上面的例子中我们使用grep命令。find命令首先匹配所有文件名为“ passwd*”的文件,例如passwd、passwd.old、passwd.bak,然后执行grep命令看看在这些文件中是否存在一个root用户。

实例5:查找文件移动到指定目录

命令:

find . -name “*.log” -exec mv {} .. \;

输出:

[root@localhost test]# ll

总计 12drwxr-xr-x 6 root root 4096 10-27 01:58 scf

drwxrwxr-x 2 root root 4096 11-12 22:49 test3

drwxrwxr-x 2 root root 4096 11-12 19:32 test4

[root@localhost test]# cd test3/

[root@localhost test3]# ll

总计 304

-rw-r–r– 1 root root 302108 11-03 06:19 log2012.log

-rw-r–r– 1 root root     61 11-12 22:44 log2013.log

-rw-r–r– 1 root root      0 11-12 22:25 log2014.log

[root@localhost test3]# find . -name “*.log” -exec mv {} .. \;

[root@localhost test3]# ll

总计 0[root@localhost test3]# cd ..

[root@localhost test]# ll

总计 316

-rw-r–r– 1 root root 302108 11-03 06:19 log2012.log

-rw-r–r– 1 root root     61 11-12 22:44 log2013.log

-rw-r–r– 1 root root      0 11-12 22:25 log2014.log

drwxr-xr-x 6 root root   4096 10-27 01:58 scf

drwxrwxr-x 2 root root   4096 11-12 22:50 test3

drwxrwxr-x 2 root root   4096 11-12 19:32 test4

[root@localhost test]#

实例6:用exec选项执行cp命令

命令:

find . -name “*.log” -exec cp {} test3 \;

输出:

[root@localhost test3]# ll

总计 0[root@localhost test3]# cd ..

[root@localhost test]# ll

总计 316

-rw-r–r– 1 root root 302108 11-03 06:19 log2012.log

-rw-r–r– 1 root root     61 11-12 22:44 log2013.log

-rw-r–r– 1 root root      0 11-12 22:25 log2014.log

drwxr-xr-x 6 root root   4096 10-27 01:58 scf

drwxrwxr-x 2 root root   4096 11-12 22:50 test3

drwxrwxr-x 2 root root   4096 11-12 19:32 test4

[root@localhost test]# find . -name “*.log” -exec cp {} test3 \;

cp: “./test3/log2014.log” 及 “test3/log2014.log” 为同一文件

cp: “./test3/log2013.log” 及 “test3/log2013.log” 为同一文件

cp: “./test3/log2012.log” 及 “test3/log2012.log” 为同一文件

[root@localhost test]# cd test3

[root@localhost test3]# ll

总计 304

-rw-r–r– 1 root root 302108 11-12 22:54 log2012.log

-rw-r–r– 1 root root     61 11-12 22:54 log2013.log

-rw-r–r– 1 root root      0 11-12 22:54 log2014.log

发表在 码农日常 | 标签为 | 留下评论

旅行青蛙史上最全攻略

https://www.miaopai.com/show/LA~pcnBsoxHbE9601-ApoKgmpHa7Ft3AraE9mQ__.htm

 

发表在 大漩涡 | 标签为 | 留下评论

nginx configuration for a RESTful API

https://stackoverflow.com/questions/28094865/nginx-configuration-for-a-restful-api

 

Replace this:

location /api/v1/ {
    try_files $uri $uri/ /apiv1.php?$args;
}

With the following inside your server block:

rewrite ^/api/v1/([^/]+)/([^/]+)/?$ /apiv1.php?class=$1&method=$2? last;

Create a php file called apiv1.php and place in the root directory of your web server with the following lines of code:

<?php
$class  = filter_input(INPUT_GET, 'class',  FILTER_SANITIZE_STRING);
$method = filter_input(INPUT_GET, 'method', FILTER_SANITIZE_STRING);

echo $class;
echo '<br />';
echo $method;

Test by visiting the following link in your browser:

http://myServer/api/v1/members/getInfo
发表在 码农日常 | 标签为 | 留下评论