一、Nginx介绍
Nginx是由俄罗斯软件工程师Igor Sysoev开发的一个高性能的HTTP和反向代理服务器,具备IMAP/POP3和SMTP服务器功能,Nginx最大的特点是对高并发的支持和高效的 负载均衡,在高并发的需求场景下,是Apache服务器不错的替代品。目前,包括新浪、腾讯等知名网站都已使用Nginx作为Web应用服务器。下面我简 单介绍一下:
nginx是一个高性能的Web和反向代理服务器,它具有很多非常优越的特性;
作为Web服务器;相比较与Apache,Nginx使用更少的资源,支持更多的并发连接,体现更高的效率,这点使Nginx尤为受到虚拟主机提供商的欢迎,能够支持高达50000个并发的连接数的响应。
作为负载均衡服务器器:Nginx既可以在内部直接支持Rails和PHP,也可以支持作为HTTP代理服务器对外惊醒服务,Nginx用C语言编写,不论是系统资源开销还是CPU使用效率都比Perlbal要好的多。
作为邮件代理服务器,Nginx同时也是一个非常优秀的邮件代理服务器(最早开发这个产品的目的之一也是作为邮件代理服务器),Last.fm描述了成功并且美妙的使用经验。
Nginx安装非常简单,配置文件非常简介(还能够支持perl语法),Bugs非常少的服务器:Nginx启动特别容易,并且几乎可以做到7*24不间断运行,即使运行数月也不需要重新启动。还能够在不间断服务的情况下进行软件版本平滑升级。
二、软件获得及帮助文档
官方地址:http://nginx.org
下载稳定版本:http://nginx.org/download/nginx-1.8.0.tar.gz
编译参数说明:http://nginx.org/en/docs/configure.html
三、Nginx的功能
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 | 1、Nginx的特性 模块化设计、较好的扩展性 高可靠性:一个master启动一或多个worker,每个worker响应多个请求 低内存消耗:10000个keepalive连接在Nginx中仅消耗2.5MB内存(官方数据) 支持热部署:不停机更新配置文件、更新日志文件、更新服务器程序版本 2、Nginx的基本功能 静态web资源服务器,能够缓存打开的文件描述符 支持http /imap/pop3/smtp 的反向代理;支持缓存、负载均衡 支持fastcgi(fpm) 模块化,非DSO机制,支持过滤器zip压缩,SSI以及图像大小调整 支持SSL 3、Nginx的扩展功能 基于名称和IP的虚拟主机 支持keepalive的保持机制 支持平滑升级 定制访问日志,支持使用日志缓存区提高日志存储性能 支持url rewrite 支持路径别名(root或 alias 指定) 支持基于IP以及用户的访问控制 支持传输速率限制,并发限制 4、Nginx的基本架构 一个master进程,生成一个或者多个worker进程,每个worker响应多个请求 事件驱动:epoll,kqueue,poll, select ,rt signals 支持sendfile,sendfile64 支持AIO 支持mmap 5、Nginx模块类型 Nginx core module: nginx的核心模块 Standard HTTP modules:nginx的标准模块 Optional HTTP modules:nginx的可选模块 Mail modules :nginx的邮件模块 3rd party modules:nginx的第三方模块 6、Nginx进程详解 主进程主要完成如下工作: 读取并验正配置信息; 创建、绑定及关闭套接字; 启动、终止及维护worker进程的个数; 无须中止服务而重新配置工作特性; 控制非中断式程序升级,启用新的二进制程序并在需要时回滚至老版本; 重新打开日志文件,实现日志滚动; 编译嵌入式perl脚本; worker进程主要完成的任务包括: 接收、传入并处理来自客户端的连接; 提供反向代理及过滤功能; nginx任何能完成的其它任务; cache loader进程主要完成的任务包括: 检查缓存存储中的缓存对象; 使用缓存元数据建立内存数据库; cache manager进程的主要任务: 缓存的失效及过期检验; |
四、Nginx安装配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 | 1、安装依赖包(CentOS 6.7) [root@mail soft] # yum -y groupinstall "Development tools,Server platform development,Desktop platform development" [root@mail soft] # yum -y install pcre-devel openssl-devel 2、编译安装Nginx [root@mail soft] # tar xf nginx-1.8.0.tar.gz [root@mail soft] # cd nginx-1.8.0 [root@mail nginx-1.8.0] # groupadd -r nginx [root@mail nginx-1.8.0] # useradd -g nginx -s /sbin/nologin -M nginx [root@mail nginx-1.8.0] # ./configure \ --prefix= /usr/local/nginx \ --sbin-path= /usr/sbin/nginx \ --conf-path= /etc/nginx/nginx .conf \ --error-log-path= /var/log/nginx/error .log \ --http-log-path= /var/log/nginx/access .log \ --pid-path= /var/run/nginx/nginx .pid \ --lock-path= /var/lock/nginx .lock \ --user=nginx \ --group=nginx \ --with-http_ssl_module \ --with-http_flv_module \ --with-http_stub_status_module \ --with-http_gzip_static_module \ --http-client-body-temp-path= /var/tmp/nginx/client/ \ --http-proxy-temp-path= /var/tmp/nginx/proxy/ \ --http-fastcgi-temp-path= /var/tmp/nginx/fcgi/ \ --http-uwsgi-temp-path= /var/tmp/nginx/uwsgi \ --http-scgi-temp-path= /var/tmp/nginx/scgi \ --with-pcre [root@mail nginx-1.8.0] # make && make install ##注意:编译后有些文件夹不会自动创建 [root@mail nginx-1.8.0] # mkdir -pv /var/tmp/nginx/{client,proxy,fcgi,uwsgi,scgi} mkdir : created directory ` /var/tmp/nginx ‘ mkdir : created directory ` /var/tmp/nginx/client ‘ mkdir : created directory ` /var/tmp/nginx/proxy ‘ mkdir : created directory ` /var/tmp/nginx/fcgi ‘ mkdir : created directory ` /var/tmp/nginx/uwsgi ‘ mkdir : created directory ` /var/tmp/nginx/scgi ‘ 这里的二进制文件是直接指定在PATH环境变量里面的,所有可以直接使用,不用导出: 配置vim,使其编辑nginx配置文件时语法着色,默认没有 [root@mail nginx-1.8.0] # cd [root@mail ~] # mkdir .vim [root@mail ~] # cp -ra /u01/soft/nginx-1.8.0/contrib/vim/* .vim [root@mail ~] # ls .vim ftdetect indent syntax 编写启动脚本: [root@mail ~] # vim /etc/rc.d/init.d/nginx #!/bin/sh # # nginx - this script starts and stops the nginx daemin # # chkconfig: - 85 15 # description: Nginx is an HTTP(S) server, HTTP(S) reverse \ # proxy and IMAP/POP3 proxy server # processname: nginx # config: /etc/nginx/nginx.conf # pidfile: /var/run/nginx.pid # Source function library. . /etc/rc .d /init .d /functions # Source networking configuration. . /etc/sysconfig/network # Check that networking is up. [ "$NETWORKING" = "no" ] && exit 0 nginx= "/usr/sbin/nginx" prog=$( basename $nginx) NGINX_CONF_FILE= "/etc/nginx/nginx.conf" lockfile= /var/lock/subsys/nginx start() { [ -x $nginx ] || exit 5 [ -f $NGINX_CONF_FILE ] || exit 6 echo -n $ "Starting $prog: " daemon $nginx -c $NGINX_CONF_FILE retval=$? echo [ $retval - eq 0 ] && touch $lockfile return $retval } stop() { echo -n $ "Stopping $prog: " killproc $prog -QUIT retval=$? echo [ $retval - eq 0 ] && rm -f $lockfile return $retval } restart() { configtest || return $? stop start } reload() { configtest || return $? echo -n $ "Reloading $prog: " killproc $nginx -HUP RETVAL=$? echo } force_reload() { restart } configtest() { $nginx -t -c $NGINX_CONF_FILE } rh_status() { status $prog } rh_status_q() { rh_status > /dev/null 2>&1 } case "$1" in start) rh_status_q && exit 0 $1 ;; stop) rh_status_q || exit 0 $1 ;; restart|configtest) $1 ;; reload) rh_status_q || exit 7 $1 ;; force-reload) force_reload ;; status) rh_status ;; condrestart|try-restart) rh_status_q || exit 0 ;; *) echo $"Usage: $0 {start|stop|status|restart|condrestart|try-restart|reload|force- reload|configtest}" exit 2 esac [root@mail ~] # chmod +x /etc/rc.d/init.d/nginx #添加可执行权限 [root@mail ~] # chkconfig --add nginx #添加到服务列表 [root@mail ~] # chkconfig nginx on #设置开机自启动 [root@mail ~] # service nginx start #启动nginx Starting nginx: [ OK ] [root@mail ~] # ss -tnl #查看是否监听80端口 [root@mail ~] # ss -tnl State Recv-Q Send-Q Local Address:Port Peer Address:Port LISTEN 0 128 *:80 *:* LISTEN 0 128 :::22 :::* LISTEN 0 128 *:22 *:* ##查看页面 [root@mail ~] # curl http://localhost <!DOCTYPE html> <html> < head > <title>Welcome to nginx!< /title > <style> body { width: 35em; margin: 0 auto; font-family: Tahoma, Verdana, Arial, sans-serif; } < /style > < /head > <body> <h1>Welcome to nginx!< /h1 > <p>If you see this page, the nginx web server is successfully installed and working. Further configuration is required.< /p > <p>For online documentation and support please refer to <a href= "http://nginx.org/" >nginx.org< /a >.<br/> Commercial support is available at <a href= "http://nginx.com/" >nginx.com< /a >.< /p > <p><em>Thank you for using nginx.< /em >< /p > < /body > < /html > #######################编译安装已经完成。 配置文件介绍 主要有两部分:分别是 main:主体部分 http{}:虚拟主机配置部分 配置指令主要以分号结尾;配置语法:directive value1 [value2 ....] 支持使用的变量 模块内置的变量 自定义变量: set var_name value 主配置段的指令类别: 用于调试和定位问题: (1)daemon [on|off]: 是否以守护进程的方式启动nginx; (2)master_press [on|off]: 是否以master /worker 模型来运行nginx; (3)error_log /path/to/error_loglevel : 指明错误日志文件级别,处于调试目的,可以使用debug级别,但次级别只有在编译nginx时使用了--with-debug选项才有效 ; 正常运行必备的配置: (1)user USERNAME [GROUPNAME]:指定运行worker的用户和用户组;例如 user nginx nginx (2)pid /path/to/nginx .pid : 指定pid文件 (3)worker_rlimit_nofile # : 指定一个worker进程能够打开的最大文件句柄数 (4)worker_rlimit_sigpending # : 指定每个用户能够发往worker信号的数量 优化性能相关的配置: (1)worker_processes # :worker进程的个数,通常是cpu核心数减1 (2)worker_cpu_affinity cpuumask :绑定worker进程至指定的CPU上 (3)timer-resolution t :时间解析度,在x86服务器上可以不用配置 (4)worker_priority NICE :调整 nice 值(-20,19); nice 值越大,越优先分配cpu 事件相关的配置; (1)accept_mutex [on|off] :内部调动用户请求至各worker时的负载均衡锁;启用时表示能够让多个worker轮流的、序列化的响应请求 (2)lock_file /path/to/lock_file :指定锁文件 (3)accept_mutex_delay #ms: 取得负载均衡锁的时间 (4)use [epoll|poll| select |rgsig]:定义使用的事件模型,建议让nginx自动选择 (5)worker_connections #:每个worker进程所能够响应的最大并发请求数 |
五、Nginx的一些基本功能实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | 1、基于用户认证: (1)、修改配置文件 server { listen 80; server_name localhost; #charset koi8-r; #access_log logs/host.access.log main; location / { root html; index index.html index.htm; auth_basic "www.bjwf125.com" ; auth_basic_user_file /www/html/ . passwd ; } } (2)、创建文档根目录以及使用httpd-tools中的htpasswd工具创建用户 [root@mail ~] # mkdir -pv /www/html mkdir : created directory ` /www ‘ mkdir : created directory ` /www/html ‘ [root@mail ~] # echo "Welcome to bjwf125" > /www/html/index.html [root@mail ~] # yum -y install httpd-tools [root@mail ~] # htpasswd -c -m /www/html/.passwd centos #创建centos用户 New password: #输入密码 Re- type new password: #再次输入 Adding password for user centos (3)、重新载入配置文件 [root@mail ~] # nginx -t #检查Nginx语法 nginx: the configuration file /etc/nginx/nginx .conf syntax is ok nginx: configuration file /etc/nginx/nginx .conf test is successful [root@mail ~] # service nginx reload #重新载入 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | 2、基于IP认证 server { listen 80; server_name localhost; #charset koi8-r; #access_log logs/host.access.log main; location / { root html; index index.html index.htm; deny 192.168.9.0 /24 ; allow all; } } 3、基于 gzip 压缩 server { listen 80; server_name localhost; #charset koi8-r; #access_log logs/host.access.log main; location / { root /www/html ; index index.html index.htm; gzip on; gzip_http_version 1.0; gzip_min_length 1000; gzip_proxied expired no-cache no-store private auth; gzip_types text /plain application /xml text /css application /x-javascript text /xml application /xml +rss text /javascript application /javascript application /json ; gzip_disable msie6 safari; } } [root@mail ~] # nginx -t [root@mail ~] # service nginx reload [root@mail ~] # cp /etc/rc.d/rc.sysinit /www/html/zip.html [root@mail ~] # ll /www/html/zip.html -h -rwxr-xr-x 1 root root 20K Jan 13 10:01 /www/html/zip .html |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | 4、定制响应头部 server { listen 80; server_name localhost; #charset koi8-r; #access_log logs/host.access.log main; location / { root /www/html ; index index.html index.htm; expires 24h; add_header bjwf125 mymail; } } [root@mail ~] # nginx -t [root@mail ~] # service nginx reload |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | 5、URL重定向 语法格式: rewrite grgex replacement [flages] flages last:一旦被当前规则匹配并重写后立即停止检查其他后续的rewrite的规则,而后通过重写后的规则重写发起请求; bleak:一旦被当前规则匹配并重写后立即停止后续的其他rewrite的规则,而后由nginx进行后续操作; redirect:返回302临时重定向 permanent:返回301永久重定向 例如: [root@mail ~] # vim /etc/nginx/nginx.conf server { listen 80; server_name localhost; #charset koi8-r; #access_log logs/host.access.log main; location / { root /www/html ; index index.html index.htm; rewrite ^ /admin/ (.*)$ /web/ $1; } } [root@mail ~] # mkdir -pv /www/html/{admin,web} [root@mail ~] # echo "mail.bjwf125.com" > /www/html/web/index.html [root@mail ~] # nginx -t [root@mail ~] # service nginx reload |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 | 6、虚拟主机 [root@mail nginx] # vim /etc/nginx/nginx.conf #注释掉http{}段中的预定义server{}段中的所有内容; 在文件末尾}前一行添加一条: include conf.d /nginx-vhost .conf; #方便后面定义,根据个人习惯而已,也可以直接在/etc/nginx/nginx.conf中配置 [root@mail nginx] # vim /etc/nginx/conf.d/nginx-vhost.conf server { listen 80; server_name www.a.com; location / { root /www/html/a ; index index.html index.htm; } } server { listen 80; server_name www.b.com; location / { root /www/html/b ; index index.html index.htm; } } [root@mail nginx] # mkdir /www/html/{a,b} -pv mkdir : created directory ` /www/html/a ‘ mkdir : created directory ` /www/html/b ‘ [root@mail nginx] # echo "www.a.com" > /www/html/a/index.html [root@mail nginx] # echo "www.b.com" > /www/html/b/index.html [root@mail nginx] # vim /etc/hosts 192.168.9.9 www.a.com 192.168.9.9 www.b.com [root@mail nginx] # service nginx reload [root@mail nginx] # curl http://www.a.com www.a.com [root@mail nginx] # curl http://www.b.com www.b.com ###虚拟主机最简单的方式已经配置完成,但是虚拟主机里面还有很多参数。 7、防盗链 (1)、定义合规的引用 valid_referers none | blocked | server_names | string ...; (2)、拒绝不合规的引用 if ($invalid referer) { rewrite ^/ http: //www .b.com /403 .html; } ##具体示例如下: [root@mail conf.d] # vim nginx-vhost.conf server { listen 80; server_name www.b.com; location / { root /www/html/b ; index index.html index.htm; valid_referers none blocked www.b.com *.b.com; if ($invalid_referer) { rewrite ^/ http: //www .b.com /403 .html; } } } [root@mail conf.d] # vim /www/html/a/index.html www.a.com <img src= "http://www.b.com/images/1.jpg" > #在a.com中引用 [root@mail conf.d] # vim /www/html/b/index.html www.b.com <img src= "http://www.b.com/images/1.jpg" > #b.com自己引用 |
测试结果:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 | 8、Nginx的反向代理 Nginx可以通过proxy模块实现反向代理功能,在作为web反向代理服务器时,Nginx复制接收客户端请求,并能够根据URL、客户端参数或者其它的处理逻辑将用户请求调度至上游服务器上(upstream server)。 Nginx在实现反向代理功能时最重要的指令为proxy_pass,它能够将location中定义的某URI代理至指定的上游服务器(组)上。如下面的示例中,location的URI将被替换为上游服务器上的newURI。 ### 例如: [root@mail conf.d] # vim nginx-vhost.conf server { listen 80; server_name www.a.com; add_header X-Via $server_addr; location / { root /www/html/a ; index index.html index.htm; } location = /node2 { proxy_pass http: //192 .168.9.11/; } } ##上游服务器必须要配置相应服务及页面 [root@mail conf.d] # service nginx reload [root@mail conf.d] # curl www.a.com <img src= "http://www.b.net/images/1.jpg" > [root@mail conf.d] # curl http://www.a.com/node1 node1.bjwf125.com (1)、缓存:Nginx作为反向代理时,能够将上游服务器的响应缓存至本地,并在后续的客户端请求同样的内容时直接从本地构造响应报文。具体参数如下: proxy_cache zone|off:定义一个用于缓存的共享内存区域,其可被多个地方调用; proxy_cache_path:定义一个保存缓存响应报文的目录,及一个保存缓存对象的键及响应元数据的共享内存区域(keys_zone=name:size),其可选参数有: levels:每级子目录名称的长度,有效值为1或2,每级之间使用冒号分隔,最多为3级; inactive:非活动缓存项从缓存中剔除之前的最大缓存时长; max_size:缓存空间大小的上限,当需要缓存的对象超出此空间限定时,缓存管理器将基于LRU算法对其进行清理; loader_files:缓存加载器(cache_loader)的每次工作过程使用为多少个文件加载元数据; loader_sleep:缓存加载器的每次迭代工作之后的睡眠时长; loader_threashold:缓存加载器的最大睡眠时长; proxy_cache_valid [ code ... ] time :用于为不同的响应设定不同时长的有效缓存时长,例如: proxy_cache_valid 200 302 10m; proxy_cache_methods [GET HEAD POST]:为哪些请求方法启用缓存功能; proxy_cache_bypass string:设定在哪种情形下,nginx将不从缓存中取数据。 示例: # vim /etc/nginx/nginx.conf http { include mime.types; default_type application /octet-stream ; proxy_cache_path /data/nginx/cache levels=1:2 keys_zone=STATIC:10m inactive=24h max_size=1g; server { listen 80; server_name node1; add_header X-Via $server_addr; location / { root /www/html/b ; index index.html index.htm; proxy_pass http: //192 .168.9.11; proxy_set_header Host $host; proxy_cache STATIC; proxy_cache_valid 200 1d; proxy_cache_valid 301 302 10m; proxy_cache_valid any 1m; proxy_cache_use_stale error timeout invalid_header updating http_500 http_502 http_503 http_504; } } } [root@mail nginx] # mkdir -pv /data/nginx/cache [root@mail nginx] # nginx -t [root@mail nginx] # service nginx reload |
缓存前请求时间
缓存后请求时间
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 | ####主要文件太小,效果不是太明显,有强迫症的同学可以自己测试。 ##此时可以查看缓存目录是否有文件生成 [root@mail ~] # ll /data/nginx/cache/ drwx------ 3 nginx nginx 4096 Jan 13 14:32 1 (2)、负载均衡:Nginx可以利用自身的upstream模块实现,upstream模块的负载均衡算法主要有三种,轮调(round-robin)、ip哈希(ip_hash)和最少连接(least_conn)三种。 upstream模块常用的指令有: ip_hash:基于客户端IP地址完成请求的分发,它可以保证来自于同一个客户端的请求始终被转发至同一个upstream服务器; keepalive:每个worker进程为发送到upstream服务器的连接所缓存的个数; least_conn:最少连接调度算法; server:定义一个upstream服务器的地址,还可包括一系列可选参数,如; weight:权重; max_fails:最大失败的连接次数,失败连接的超时时长由fail_timeout指定; fail_timeout:等待请求的目录服务器发送响应的时长; backup:用于fallback的目的,所有服务均故障时才启动此服务器; down:手动标记其不再处理任何请求; 示例: # vim /etc/nginx/nginx.conf http { upstream web { server 192.168.9.11:80 max_fails=3 fail_timeout=10s; server 192.168.9.13:80 max_fails=3 fail_timeout=10s; server 127.0.0.1:8080 backup; } server { listen 80; server_name www.c.net; add_header X-Via $server_addr; location / { root /www/html/b ; index index.html index.htm; proxy_pass http: //web ; } } server { listen 8080; server_name 127.0.0.1; location / { root /www/html/b ; index index.html index.htm; } } [root@mail ~] # curl http://www.c.net 192.168.9.11 [root@mail ~] # curl http://www.c.net 192.168.9.13 ##停掉上游两台服务器后: [root@mail ~] # curl http://www.c.net Sorry #####Nginx的基本功能基本完成 |
The end
有关Nginx的基本配置及一般用法就写到这里了,第一次写Nginx的博客,写的比较乱,比较杂,敬请谅解,有什么不对的地方,麻烦朋友们告诉我。以上为个人学习整理,如有错漏,大神勿喷。。。。。
本文出自 “事在人为,知在天意” 博客,请务必保留此出处http://yangsj.blog.51cto.com/8702844/1794072
原文地址:http://yangsj.blog.51cto.com/8702844/1794072