一、简介

1. 什么是Nginx

介绍

Nginx是一款高性能的http 服务器/反向代理服务器及电子邮件(IMAP/POP3/SMTP)代理服务器。由俄罗斯的程序设计师Igor Sysoev所开发,官方测试nginx能够支支撑5万并发链接,并且cpu、内存等资源消耗却非常低,运行非常稳定。开源、免费

常用服务器

  • MS IIS ==> asp.net
  • Weblogic、Jboss ==> 传统行业 ERP/物流/电信/金融
  • Tomcat、Jetty ==> J2EE
  • Apache、Nginx ==> 静态服务,反向代理

https://news.netcraft.com/archives/2020/05/26/may-2020-web-server-survey.html

Nginx的应用场景

  • http服务器。Nginx是一个http服务可以独立提供http服务。可以做网页静态服务器。
  • 虚拟主机。可以实现在一台服务器虚拟出多个网站。例如个人网站使用的虚拟主机。
  • 反向代理,负载均衡。当网站的访问量达到一定程度后,单台服务器不能满足用户的请求时,需要用多台服务器集群可以使用nginx做反向代理。并且多台服务器可以平均分担负载,不会因为某台服务器负载高宕机而某台服务器闲置的情况

一般Java项目整体架构

image.png

2. 正向代理与反向代理

1. 正向代理

正向代理类似一个跳板机,通过一个中间服务器(代理服务器),代理访问外部资源返回数据到代理服务器,再由代理服务器发送至客户端。image-20210131001956131.png
客户端必须设置正向代理服务器,当然前提是要知道正向代理服务器的IP地址,还有代理程序的端口
正向代理的用途

  1. 访问原来无法访问的资源,如google
  2. 可以做缓存,加速访问资源
  3. 对客户端访问授权,上网进行认证
  4. 代理可以记录用户访问记录(上网行为管理),对外隐藏用户信息

2. 反向代理

初次接触方向代理的感觉是,客户端是无感知代理的存在的,反向代理对外都是透明的,访问者者并不知道自己访问的是一个代理。因为客户端不需要任何配置就可以访问。

反向代理(Reverse Proxy)实际运行方式是指以代理服务器来接受internet上的连接请求,然后将请求转发给内部网络上的服务器,并将从服务器上得到的结果返回给internet上请求连接的客户端,此时代理服务器对外就表现为一个服务器。

反向代理,负载均衡。当网站的访问量达到一定程度后,单台服务器不能满足用户的请求时,需要用多台服务器集群可以使用nginx做反向代理。并且多台服务器可以平均分担负载,不会因为某台服务器负载高宕机而某台服务器闲置的情况。

反向代理的作用:

  1. 保证内网安全,可以使用反向代理提供WAF功能,阻止web攻击

image-20210131003902411.png

  1. 负载均衡,当网站的访问量达到一定程度后,单台服务器不能满足用户的请求时,需要用多台服务器集群可以使用nginx做反向代理。并且多台服务器可以平均分担负载,不会因为某台服务器负载高宕机而某台服务器闲置的情况

负载均衡的策略:轮询(默认)、随机、权重、就近
image-20210131004010982.png

3. 正向代理与反向代理的区别

  1. 正向代理中,proxy和client同属一个LAN,对server透明;
  2. 反向代理中,proxy和server同属一个LAN,对client透明。

image-20210131004342244.png

3. Nginx基本工作机制

1. Nginx显示首页过程

image.png
对应 /usr/local/nginx/conf/nginx.conf 中的配置

  1. server {
  2. listen 80;
  3. server_name localhost;
  4. location / {
  5. root html;
  6. index index.html index.htm;
  7. }
  8. }

2. Nginx的进程模型

基本模型

Nginx使用Master进程和Worker进程模型
image.png

  • 多进程相对于多线程,内存独立,减少线程安全的问题
  • 使用ps命令查看正在运行的nginx进程

    ps -ef | grep nginx
    
  • 在配置文件中可以配置worker的数量

    worker_processes  1;
    

Worker抢占机制

image.png

Nginx使用异步非阻塞的方式来处理请求

在nginx.conf中可以配置进程处理客户端的数量

events {
    #默认使用linux的epoll模型
    use epoll;
    #一个worker可以处理的连接数量
    worker_connections  1024;
}

同步与异步,阻塞与非阻塞

我们提到了阻塞与非阻塞、同步与异步,很多同学可能会认为同步就是阻塞,异步就是非阻塞,非也非也~~这一节咱们来聊一聊他们的概念,有啥区别,如果学习过的可以当做复习,如果不太清楚的,可以好好的了解一番,因为这些概念往往在面试过程中有可能会被面试官问到


四个概念两两组合,会形成4个新的概念,如下:

  1. 同步阻塞:客户端发送请求给服务端,此时服务端处理任务时间很久,则客户端则被服务端堵塞了,所以客户端会一直等待服务端的响应,此时客户端不能做其他任何事,服务端也不会接受其他客户端的请求。这种通信机制比较简单粗暴,但是效率不高。

  2. 同步非阻塞:客户端发送请求给服务端,此时服务端处理任务时间很久,这个时候虽然客户端会一直等待响应,但是服务端可以处理其他的请求,过一会回来处理原先的。这种方式很高效,一个服务端可以处理很多请求,不会在因为任务没有处理完而堵着,所以这是非阻塞的。

  3. 异步阻塞:客户端发送请求给服务端,此时服务端处理任务时间很久,但是客户端不会等待服务器响应,它可以做其他的任务,等服务器处理完毕后再把结果响应给客户端,客户端得到回调后再处理服务端的响应。这种方式可以避免客户端一直处于等待的状态,优化了用户体验,其实就是类似于网页里发起的ajax异步请求。

  4. 异步非阻塞:客户端发送请求给服务端,此时服务端处理任务时间很久,这个时候的任务虽然处理时间会很久,但是客户端可以做其他的任务,因为他是异步的,可以在回调函数里处理响应;同时服务端是非阻塞的,所以服务端可以去处理其他的任务,如此,这个模式就显得非常的高效了


以上四点,除了第三点,其余的分别为BIO/NIO/AIO,面试官如果问你“请简述一下BIO/NIO/AIO之间的概念与区别”,那么你就可以组织一下语言来回答,或者通过如下生活实例来阐述也是可以的:

  1. BIO:我去上厕所,这个时候坑位都满了,我必须等待坑位释放了,我才能上吧?!此时我啥都不干,站在厕所里盯着,过了一会有人出来了,我就赶紧蹲上去。

  2. NIO:我去上厕所,这个时候坑位都满了,没关系,哥不急,我出去抽根烟,过会回来看看有没有空位,如果有我就蹲,如果没有我出去接着抽烟或者玩会手机。

  3. 异步阻塞:我去上厕所,这个时候坑位都满了,没事我等着,等有了新的空位,让他通知我就行,通知了我,我就蹲上去。

  4. AIO:我去上厕所,这个时候坑位都满了,没事,我一点也不急,我去厕所外面抽根烟再玩玩手机,等有新的坑位释放了,会有人通知我的,通知我了,我就可以进去蹲了

小结:异步的优势显而易见,大大优化用户体验,非阻塞使得系统资源开销远远小于阻塞模式,因为系统不需要创建新的进程(或线程),大大地节省了系统的资源,如此多出来的系统资源可以给其他的中间件去服务了。

二、Nginx安装

1. 普通安装方式

1. 安装前提条件

GCC

nginx是C语言开发,建议在linux上运行,本教程使用Centos7作为安装环境。

安装nginx需要先将官网下载的源码进行编译,编译依赖gcc环境,如果没有gcc环境,需要安装gcc

yum install gcc-c++

PCRE

PCRE(Perl Compatible Regular Expressions)是一个Perl库,包括 perl 兼容的正则表达式库。nginx的http模块使用pcre来解析正则表达式,所以需要在linux上安装pcre库

yum install -y pcre pcre-devel

注:pcre-devel是使用pcre开发的一个二次开发库。nginx也需要此库

zlib

zlib库提供了很多种压缩和解压缩的方式,nginx使用zlib对http包的内容进行gzip,所以需要在linux上安装zlib库

yum install -y zlib zlib-devel

openssl

OpenSSL 是一个强大的安全套接字层密码库,囊括主要的密码算法、常用的密钥和证书封装管理功能及SSL协议,并提供丰富的应用程序供测试或其它目的使用
nginx不仅支持http协议,还支持https(即在ssl协议上传输http),所以需要在linux安装openssl库

yum install -y openssl openssl-devel

2. Nginx的安装步骤

http://nginx.org/en/download.html

  1. 把nginx的压缩包上传到服务器
  2. 解压

    tar -zxvf nginx-1.16.1.tar.gz
    
  3. 编译之前,先创建nginx临时目录,如果不创建,在启动nginx的过程中会报错

    #-p是递归创建文件夹
    mkdir /var/temp/nginx -p
    
  4. 配置参数如下:(直接在nginx的解压路径执行下面的操作)

    ./configure \
    --prefix=/usr/local/nginx \
    --pid-path=/var/run/nginx/nginx.pid \
    --lock-path=/var/lock/nginx.lock \
    --error-log-path=/var/log/nginx/error.log \
    --http-log-path=/var/log/nginx/access.log \
    --with-http_gzip_static_module \
    --http-client-body-temp-path=/var/temp/nginx/client \
    --http-proxy-temp-path=/var/temp/nginx/proxy \
    --http-fastcgi-temp-path=/var/temp/nginx/fastcgi \
    --http-uwsgi-temp-path=/var/temp/nginx/uwsgi \
    --http-scgi-temp-path=/var/temp/nginx/scgi
    

    配置命令解释:

命令 解释
–prefix 指定nginx安装目录
–pid-path 指向nginx的pid
–lock-path 锁定安装文件,防止被恶意篡改或误操作
–error-log 错误日志
–http-log-path http日志
–with-http_gzip_static_module 启用gzip模块,在线实时压缩输出数据流
–http-client-body-temp-path 设定客户端请求的临时目录
–http-proxy-temp-path 设定http代理临时目录
–http-fastcgi-temp-path 设定fastcgi临时目录
–http-uwsgi-temp-path 设定uwsgi临时目录
–http-scgi-temp-path 设定scgi临时目录

注意:上边将临时文件目录指定为/var/temp/nginx,需要在/var下创建temp及nginx目录

  1. 编译make
  2. 安装make install
  3. 运行(进入到安装目录运行,/usr/local/nginx)
    ./nginx
    
  • 停止:_./nginx -s stop_
  • 重新加载:_./nginx -s reload_
  • 打开防火墙的80端口:_firewall-cmd --zone=public --add-port=80/tcp_
  • 查看端口开放情况:_firewall-cmd --list-ports_
  1. Nginx基本目录

_cd /usr/local/nginx_ 进入到nginx的安装目录

Conf: nginx:的配置文件路径 Html: nginx:的默认的静态文件资源路径 Sbin: nginx:的执行命令的路径

3. Nginx默认路径

  • Nginx配置路径:_/etc/nginx/_
  • 命令程序:_/usr/sbin/nginx_
  • 错误日志:_/var/log/nginx/error.log_
  • 访问日志:_/var/log/nginx/access.log_
  • 默认站点目录:_/usr/share/nginx/html_

4. Nginx常用命令

进入到nginx安装目录(/usr/local/nginx)下的sbin文件夹执行命令

  • 启动:_nginx_
  • 测试nginx配置是否正确:_nginx -t_
  • 重启:nginx -s reload
  • 设置conf文件:_nginx -c /usr/conf/nginx.conf_
  • 查看nginx的进程号:_ps -ef |grep nginx_
  • nginx服务停止:_nginx -s stop / kill -9 pid_
  • 等待所有连接断开后再关闭:_nginx -s quit_
  • 查看nginx相关配置:_nginx -V_

基本启动方式

  • 进入到nginx的安装目录(—prefix=/usr/local/nginx )
  • 进入到sbin目录下
  • 使用./nginx启动

5. Nginx大致配置

基本配置

_/etc/nginx/nginx.conf_:文件中对nginx进行基础配置

#运行nginx的用户
user  nginx;
#工作进程的数量,可以根据CPU的核心总数来设置,一般都是小于或者等于物理cpu核心数,auto表示自动去匹配cup核心数来启动worker进程数量
worker_processes  auto;

#error_log表示指定nginx错误日志存放文件
error_log  /var/log/nginx/error.log warn;
#pid表示指定pid文件,pid文件就是存放nginx主控进程的进程号的,如果nginx没有运行或者停止了服务,那么pid文件也会跟着消失
pid        /var/run/nginx.pid;

#events此配置段表示配置有关事件驱动相关的配置
events {
    #每个worker进程所能够打开的最大并发连接数
    worker_connections  1024;
}


http {
    #支持的媒体类型
    include       /etc/nginx/mime.types;
    #默认的类型
    default_type  application/octet-stream;
    #日志格式
    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';
    #访问日志文件的位置
    access_log  /var/log/nginx/access.log  main;

    #是否调用sendfile函数来输出文件(高效文件传输模式)
    sendfile        on;
    #tcp_nopush     on;

    #连接超时时间 (单位:秒)
    keepalive_timeout  65;

    #启用Gizp压缩
    #gzip  on;

    #引入外部配置文件
    include /etc/nginx/conf.d/*.conf;
}


实现负载均衡的相关配置

根据核心配置文件中引入外部配置文件的地址,创建对应的 .conf 配置文件

#负载均衡服务器集群的名称
upstream  test.com {  
        #服务器集群相关配置,连接每一个被代理的服务器以及其中的Tomcat
        server    192.168.31.216:8080;  #weight=1;
        server    192.168.31.216:8081;  #weight=2; weight是权重的意思,权重越大nginx分配的概率越大
}

#虚拟主机配置(可虚拟多个主机)
server {
    #nginx监听的端口
    listen       80;
    #虚拟主机名称,(使用域名或者IP)
    server_name  localhost;

    #charset koi8-r;
    #access_log  /var/log/nginx/host.access.log  main;

    #监听访问路径 /为所有访问路径
    location / {
        #监听到访问后,跳转到设置的服务器集群中,分配访问(//后对应upstream集群的名称)
        proxy_pass http://test.com;
        proxy_redirect default;

        #监听到访问后查找该root地址,index为跳转的页面
        #root   /usr/share/nginx/html;
        #index  index.html index.htm;
    }

    #error_page  404              /404.html;

    # redirect server error pages to the static page /50x.html
    #错误页面跳转
    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /usr/share/nginx/html;
    }
}

2. 使用Docker安装

下载nginx和tomcat的镜像:_docker pull nginx_

创建nginx本地目录,稍后挂载到容器内:_mkdir -p /usr/nginx/html /usr/nginx/conf/ /usr/nginx/logs_

新增修改 /usr/ngin/conf/nginx.conf 文件:

user  nginx;
worker_processes  1;

error_log  /var/log/nginx/error.log warn;
pid        /var/run/nginx.pid;


events {
    worker_connections  1024;
}


http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for" "$upstream_addr"';

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

    sendfile        on;
    #tcp_nopush     on;

    keepalive_timeout  65;

    #gzip  on;

        # 负载均衡转发到下面地址
    upstream tomcat {
        server 172.17.0.2:8080;
        server 172.17.0.4:8080;
    }

    server {
        listen 80;
        server_name localhost;

                # 后台请求访问地址
        location / {
            proxy_pass http://tomcat;
            proxy_redirect off;
            index index.html index.htm;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Real-Port $remote_port;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        }

                # 静态文件访问地址
        location /static/ {
            alias /usr/share/nginx/html/;
        }
    }

    include /etc/nginx/conf.d/*.conf;
}

启动Nginx:

docker run -d -p 80:80 --name nginx -v /usr/nginx/html:/usr/share/nginx/html -v /usr/nginx/conf/nginx.conf:/etc/nginx/nginx.conf -v /usr/nginx/logs:/var/log/nginx nginx

三、Nginx的配置

  1. 使用文本编辑命令打开nginx目录下的conf/nginx.conf文件
  2. 配置文件主要由四部分组成:main(全区设置),server(主机配置),upstream(负载均衡服务器设置),和location(URL匹配特定位置设置)

image.png

1. 核心配置

  1. 设置worker进程的用户,指的linux中的用户,会涉及到nginx操作目录或文件的一些权限,默认为nobody | user root; | | —- |
  1. worker进程工作数设置,一般来说CPU有几个,就设置几个,或者设置为N-1也行 | worker_processes 1; | | —- |
  1. nginx 日志级别debug | info | notice | warn | error | crit | alert | emerg,错误级别从左到右越来越大

  2. 设置nginx进程 pid | pid logs/nginx.pid; | | —- |

  1. 设置工作模式
    | events {
    # 默认使用epoll
    use epoll;
    # 每个worker允许连接的客户端最大连接数
    worker_connections 10240;
    } | | —- |
  1. http 是指令块,针对http网络传输的一些指令配置 | http {
    } | | —- |
  1. include 引入外部配置,提高可读性,避免单个配置文件过大 | include mime.types; | | —- |
  1. 设定日志格式,main为定义的格式名称,如此 access_log 就可以直接使用这个变量了

image.png

  • $remote_addr:客户端ip
  • $remote_user:远程客户端用户名,一般为:’-’
  • $time_local:时间和时区
  • $request:请求的url以及method
  • $status:响应状态码
  • $body_bytes_send:响应客户端内容字节数
  • $http_referer:记录用户从哪个链接跳转过来的
  • $http_user_agent:用户所使用的代理,一般来时都是浏览器
  • $http_x_forwarded_for:通过代理服务器来记录客户端的ip
  1. sendfile 使用高效文件传输,提升传输性能。启用后才能使用tcp_nopush,是指当数据表累积一定大小后才发送,提高了效率。 | sendfile on;
    tcp_nopush on; | | —- |
  1. keepalive_timeout设置客户端与服务端请求的超时时间,保证客户端多次请求的时候不会重复建立新的连接,节约资源损耗。 | #keepalive_timeout 0;
    keepalive_timeout 65; | | —- |
  1. gzip启用压缩,html/js/css压缩后传输会更快 | gzip on; | | —- |
  1. server可以在http指令块中设置多个虚拟主机
  • listen 监听端口
  • server_name localhost、ip、域名
  • location 请求路由映射,匹配拦截
  • root 请求位置
  • index 首页设置 | server {
    listen 88;
    server_name localhost;

    location / {
    root html;
    index index.html index.htm;
    }
    } | | —- |

2. 全局配置

  1. Nginx的worker进程运行用户以及用户组

    user  nobody nobody;
    
  2. Nginx开启的进程数

    worker_processes  1;
    #worker_processes auto;
    #error_log  logs/error.log  info;
    
  3. 指定进程ID存储文件位置

    pid        logs/nginx.pid;
    

3. 事件配置

events {
    #use [ kqueue | rtsig | epoll | /dev/poll | select | poll ]; 
    #epoll模型是Linux 2.6以上版本内核中的高性能网络I/O模型,如果跑在FreeBSD上面,就用kqueue模型。
    use epoll;

    #每个进程可以处理的最大连接数,理论上每台nginx服务器的最大连接数为worker_processes*worker_connections。理论值:worker_rlimit_nofile/worker_processes
    #注意:最大客户数也由系统的可用socket连接数限制(~ 64K),所以设置不切实际的高没什么好处
    worker_connections  65535;    

    #worker工作方式:串行(一定程度降低负载,但服务器吞吐量大时,关闭使用并行方式)
    #multi_accept on; 
}

4. http参数(可以配置多个虚拟主机)

#文件扩展名与文件类型映射表
    include mime.types;
    #默认文件类型
    default_type application/octet-stream;

#日志相关定义
    #log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
    #                  '$status $body_bytes_sent "$http_referer" '
    #                  '"$http_user_agent" "$http_x_forwarded_for"';
    #定义日志的格式。后面定义要输出的内容。
    #1.$remote_addr 与$http_x_forwarded_for 用以记录客户端的ip地址;
    #2.$remote_user :用来记录客户端用户名称;
    #3.$time_local :用来记录访问时间与时区;
    #4.$request  :用来记录请求的url与http协议;
    #5.$status :用来记录请求状态; 
    #6.$body_bytes_sent :记录发送给客户端文件主体内容大小;
    #7.$http_referer :用来记录从那个页面链接访问过来的;
    #8.$http_user_agent :记录客户端浏览器的相关信息
    #连接日志的路径,指定的日志格式放在最后。
    #access_log  logs/access.log  main;
    #只记录更为严重的错误日志,减少IO压力
    error_log logs/error.log crit;
    #关闭日志
    #access_log  off;

    #默认编码
    #charset utf-8;
    #服务器名字的hash表大小
    server_names_hash_bucket_size 128;
    #客户端请求单个文件的最大字节数
    client_max_body_size 8m;
    #指定来自客户端请求头的hearerbuffer大小
    client_header_buffer_size 32k;
    #指定客户端请求中较大的消息头的缓存最大数量和大小。
    large_client_header_buffers 4 64k;
    #开启高效传输模式。
    sendfile        on;
    #防止网络阻塞
    tcp_nopush on;
    tcp_nodelay on;

    #客户端连接超时时间,单位是秒
    keepalive_timeout 60;
    #客户端请求头读取超时时间
    client_header_timeout 10;
    #设置客户端请求主体读取超时时间
    client_body_timeout 10;
    #响应客户端超时时间
    send_timeout 10;

#FastCGI相关参数是为了改善网站的性能:减少资源占用,提高访问速度。
    fastcgi_connect_timeout 300;
    fastcgi_send_timeout 300;
    fastcgi_read_timeout 300;
    fastcgi_buffer_size 64k;
    fastcgi_buffers 4 64k;
    fastcgi_busy_buffers_size 128k;
    fastcgi_temp_file_write_size 128k;

#gzip模块设置
    #开启gzip压缩输出
    gzip on; 
    #最小压缩文件大小,小于这个数就不会压缩
    gzip_min_length 1k; 
    #压缩缓冲区
    gzip_buffers 4 16k;
    #压缩版本(默认1.1,前端如果是squid2.5请使用1.0)
    gzip_http_version 1.0;
    #压缩等级 1-9 等级越高,压缩效果越好,节约宽带,但CPU消耗大
    gzip_comp_level 2;
    #压缩类型,默认就已经包含text/html,所以下面就不用再写了,写上去也不会有问题,但是会有一个warn。
    gzip_types text/plain application/x-javascript text/css application/xml;
    #前端缓存服务器缓存经过压缩的页面

gzip_vary on;

5. 虚拟主机监控配置

#虚拟主机定义
    server {
        #监听端口
        listen       80;
        #访问域名
        server_name  localhost;
        #编码格式,若网页格式与此不同,将被自动转码
        #charset koi8-r;
        #虚拟主机访问日志定义
        #access_log  logs/host.access.log  main;
        #对URL进行匹配
        location / {
            #访问路径,可相对(相对于Nginx的安装路径)也可绝对路径(linux操作系统的/根据 /usr/local/nginx/html)
            root   html;
            #首页文件。以下按顺序匹配
            index  index.html index.htm;
        }

#错误信息返回页面
        #error_page  404              /404.html;
        # redirect server error pages to the static page /50x.html
        #
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }

#访问URL以.php结尾则自动转交给127.0.0.1
        # proxy the PHP scripts to Apache listening on 127.0.0.1:80
        #
        #location ~ \.php$ {
        #    proxy_pass   http://127.0.0.1;
        #}
#php脚本请求全部转发给FastCGI处理
        # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
        #
        #location ~ \.php$ {
        #    root           html;
        #    fastcgi_pass   127.0.0.1:9000;
        #    fastcgi_index  index.php;
        #    fastcgi_param  SCRIPT_FILENAME  /scripts$fastcgi_script_name;
        #    include        fastcgi_params;
        #}

#禁止访问.ht页面 (需ngx_http_access_module模块)
        # deny access to .htaccess files, if Apache's document root
        # concurs with nginx's one
        #
        #location ~ /\.ht {
        #    deny  all;
        #}
    }
#HTTPS虚拟主机定义
    # HTTPS server
    #
    #server {
    #    listen       443 ssl;
    #    server_name  localhost;
    #    ssl_certificate      cert.pem;
    #    ssl_certificate_key  cert.key;
    #    ssl_session_cache    shared:SSL:1m;
    #    ssl_session_timeout  5m;
    #    ssl_ciphers  HIGH:!aNULL:!MD5;
    #    ssl_prefer_server_ciphers  on;
    #    location / {
    #        root   html;
    #        index  index.html index.htm;
    #    }
    #}

6. nginx状态监控

#Nginx运行状态,StubStatus模块获取Nginx自启动的工作状态(编译时要开启对应功能)
        #location /NginxStatus {
        #    #启用StubStatus的工作访问状态    
        #    stub_status    on;
        #    #指定StubStaus模块的访问日志文件
        #    access_log    logs/Nginxstatus.log;
        #    #Nginx认证机制(需Apache的htpasswd命令生成)
        #    #auth_basic    "NginxStatus";
        #    #用来认证的密码文件
        #    #auth_basic_user_file    ../htpasswd;    
        #}
访问:http://IP/NginxStatus(测试就不加密码验证相关)

7. Nginx解决跨域问题

server{
        listen 5000;
        server_name localhost;
        location = / {
            proxy_pass http://localhost:3000/;
        }
        location /test {
            proxy_pass http://localhost:3000/test;

            #   指定允许跨域的方法,*代表所有
            add_header Access-Control-Allow-Methods *;

            #   预检命令的缓存,如果不缓存每次会发送两次请求
            add_header Access-Control-Max-Age 3600;
            #   带cookie请求需要加上这个字段,并设置为true
            add_header Access-Control-Allow-Credentials true;

            #   表示允许这个域跨域调用(客户端发送请求的域名和端口) 
            #   $http_origin动态获取请求客户端请求的域   不用*的原因是带cookie的请求不支持*号
            add_header Access-Control-Allow-Origin $http_origin;

            #   表示请求头的字段 动态获取
            add_header Access-Control-Allow-Headers 
            $http_access_control_request_headers;

            #   OPTIONS预检命令,预检命令通过时才发送请求
            #   检查请求的类型是不是预检命令
            if ($request_method = OPTIONS){
                return 200;
            }
        }
    }

8. 防盗链配置

在server中添加配置

#对源站点验证
valid_referers *.xyao.com; 
#非法引入会进入下方判断
if ($invalid_referer) {
    return 404;
}

9. Nginx缓存设置

Nginx控制浏览器缓存

使用expires设置过期时间

location /static{
      alias /home/html
      # expires 10s;
    # expires @22h30m; #指定时间
    # expires -1h; #缓存提前过期
    # expires epoch;
    # expires off;
      expires max;
}

在响应头中会有Cache-Control或者Expires字段控制过期的时间

Nginx缓存其他服务器数据

  1. 浏览器缓存:加速用户访问,提升单个用户(浏览器访问者)体验,缓存在本地

    location /files {
    alias /home/imooc;
    # expires 10s;
    # expires @22h30m;
    # expires -1h;
    # expires epoch;
    # expires off;
    expires max;
    }
    
  2. Nginx缓存

  • 缓存在nginx端,提升所有访问到nginx这一端的用户
  • 提升访问上游(upstream)服务器的速度
  • 用户访问仍然会产生请求流量

image.png

# proxy_cache_path 设置缓存目录
#       keys_zone 设置共享内存以及占用空间大小
#       max_size 设置缓存大小
#       inactive 超过此时间则被清理
#       use_temp_path 临时目录,使用后会影响nginx性能
proxy_cache_path /usr/local/nginx/upstream_cache keys_zone=mycache:5m max_size=1g inactive=1m use_temp_path=off;
location / {
    proxy_pass  http://tomcats;

    # 启用缓存,和keys_zone一致
    proxy_cache mycache;
    # 针对200和304状态码缓存时间为8小时
    proxy_cache_valid   200 304 8h;
}

10. 反向代理

以下配置追加在HTTP的全局变量中

#nginx跟后端服务器连接超时时间(代理连接超时)
proxy_connect_timeout      5;
#后端服务器数据回传时间(代理发送超时)
proxy_send_timeout         5;
#连接成功后,后端服务器响应时间(代理接收超时)
proxy_read_timeout         60;
#设置代理服务器(nginx)保存用户头信息的缓冲区大小
proxy_buffer_size          16k;
#proxy_buffers缓冲区,网页平均在32k以下的话,这样设置
proxy_buffers              4 32k;
#高负荷下缓冲大小(proxy_buffers*2)
proxy_busy_buffers_size    64k;
#设定缓存文件夹大小,大于这个值,将从upstream服务器传
proxy_temp_file_write_size 64k;
#反向代理缓存目录
proxy_cache_path /data/proxy/cache levels=1:2 keys_zone=cache_one:500m inactive=1d max_size=1g;
#levels=1:2 设置目录深度,第一层目录是1个字符,第2层是2个字符
#keys_zone:设置web缓存名称和内存缓存空间大小
#inactive:自动清除缓存文件时间。
#max_size:硬盘空间最大可使用值。
#指定临时缓存文件的存储路径(路径需和上面路径在同一分区)
proxy_temp_path 
/data/proxy/temp

#服务配置
server {
    #侦听的80端口
    listen       80;
    server_name  localhost;
    location / {
        #反向代理缓存设置命令(proxy_cache zone|off,默认关闭所以要设置)
        proxy_cache cache_one;
        #对不同的状态码缓存不同时间
        proxy_cache_valid 200 304 12h;
        #设置以什么样参数获取缓存文件名
        proxy_cache_key $host$uri$is_args$args;
        #后7端的Web服务器可以通过X-Forwarded-For获取用户真实IP
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr; 
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 

        #代理设置
        proxy_pass   http://IP; 
        #文件过期时间控制
        expires    1d;
    }
    #配置手动清除缓存(实现此功能需第三方模块 ngx_cache_purge)
    #http://www.123.com/2017/0316/17.html访问
    #http://www.123.com/purge/2017/0316/17.html清楚URL缓存
    location ~ /purge(/.*) {
        allow    127.0.0.1;
        deny    all;
        proxy_cache_purge    cache_one    $host$1$is_args$args;
    }
    #设置扩展名以.jsp、.php、.jspx结尾的动态应用程序不做缓存
    location ~.*\.(jsp|php|jspx)?$ { 
        proxy_set_header Host $host; 
        proxy_set_header X-Real-IP $remote_addr; 
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 

        proxy_pass http://http://IP;
    }
}

11. 负载均衡

#负载均衡服务器池
upstream my_server_pool {
    #调度算法
    #1.轮循(默认)(weight轮循权值)
    #2.ip_hash:根据每个请求访问IP的hash结果分配。(会话保持)
    #3.fair:根据后端服务器响应时间最短请求。(upstream_fair模块)
    #4.url_hash:根据访问的url的hash结果分配。(需hash软件包)
    #参数:
    #down:表示不参与负载均衡
    #backup:备份服务器
    #max_fails:允许最大请求错误次数
    #fail_timeout:请求失败后暂停服务时间。
    server 192.168.1.109:80 weight=1 max_fails=2 fail_timeout=30;
    server 192.168.1.108:80 weight=2 max_fails=2 fail_timeout=30;
}
#负载均衡调用
server {
    ...
    location / {
        proxy_pass http://my_server_pool;
    }
}

12. URL重写

#根据不同的浏览器URL重写
if($http_user_agent ~ Firefox){
rewrite ^(.*)$  /firefox/$1 break; 
}
if($http_user_agent ~ MSIE){
rewrite ^(.*)$  /msie/$1 break; 
}

#实现域名跳转
location / {
    rewrite ^/(.*)$ https://web8.example.com$1 permanent;
}

13. IP限制

#限制IP访问
location / {
    deny 192.168.0.2;
    allow 192.168.0.0/24;
    allow 192.168.1.1;
    deny all;
}

四、动静分离

1. 技术介绍

  1. 为了提高网站的响应速度,减轻程序服务器(Tomcat,Jboss等)的负载,对于静态资源比如图片,js,css等文件,我们可以在反向代理服务器中进行缓存,这样浏览器在请求一个静态资源时,代理服务器就可以直接处理,而不用将请求转发给后端服务器。用户请求的动态文件比如servlet,jsp则转发给Tomcat,Jboss服务器处理,这就是动静分离。这也是反向代理服务器的一个重要的作用。
    本文的动静分离主要是通过nginx+tomcat来实现,其中nginx处理图片、html、JS、CSS等静态文件,tomcat处理jsp、servlet等动态请求。

  2. 以下架构虽然实现了动静分离,但是服务器还要专门开放8080端口,将来要是有多个tomcat还要开发多个端口,并不是很好的选择

image.png

  1. 可以使用nginx做代理服务器,然后根据location对请求的路径进行分发

image.png

2. 简化配置

server {
listen       88;
server_name  localhost;
#静态资源
    location ~* \.(png|apk|html|js|css)$ {
        root /upload;
    }
    #动态资源
location / {
       proxy_pass http://192.168.71.101:8080;
}
}

如果出现无法访问的情况,可以将当前用户设置为root

user  root;

3. location语法详解

1. 语法规则

location [=|~|~*|^~] /uri/ { … }
  • = 开头表示精确匹配
  • ^~ 开头表示uri以某个常规字符串开头,理解为匹配 url路径即可。nginx不对url做编码,因此请求为/static/20%/aa,可以被规则^~ /static/ /aa匹配到(注意是空格)。以xx开头
  • ~ 开头表示区分大小写的正则匹配 以xx结尾
  • ~* 开头表示不区分大小写的正则匹配 以xx结尾
  • !~!~* 分别为区分大小写不匹配及不区分大小写不匹配的正则
  • / 通用匹配,任何请求都会匹配到。

2. 优先级

首先精确匹配 =-》其次以xx开头匹配^~-》然后是按文件中顺序的正则匹配-》最后是交给 / 通用匹配

3. 规则案例

=:精确匹配
location = / {
   #规则A
}
location = /login {
   #规则B
}
以某个字符路径开头
location ^~ /static/ {
   #规则C
}
location ~ \.(gif|jpg|png|js|css)$ {
   #规则D,注意:是根据括号内的大小写进行匹配。括号内全是小写,只匹配小写
}

~*:匹配正则表达式,不区分大小写
location ~* \.png$ {
   #规则E
}
#符合图片的显示
location ~* .(GIF|jpg|png|jpeg) {
    root /home;
}
~:匹配正则表达式,区分大小写
#GIF必须大写才能匹配到
location ~ .(GIF|jpg|png|jpeg) {
    root /home;
}

location !~ \.xhtml$ {
   #规则F
}
location !~* \.xhtml$ {
   #规则G
}
location / {
   #规则H
}

那么产生的效果如下:

访问根目录/,比如http://localhost/ 将匹配规则A

访问 http://localhost/login 将匹配规则B,http://localhost/register 则匹配规则H

访问 http://localhost/static/a.html 将匹配规则C

访问 http://localhost/a.gif, http://localhost/b.jpg 将匹配规则D和规则E,但是规则D顺序优先,规则E不起作用,而 http://localhost/static/c.png 则优先匹配到规则C

访问 http://localhost/a.PNG 则匹配规则E,而不会匹配规则D,因为规则E不区分大小写。

访问 http://localhost/a.xhtml 不会匹配规则F和规则G,

http://localhost/a.XHTML不会匹配规则G,(因为!)。规则F,规则G属于排除法,符合匹配规则也不会匹配到,所以想想看实际应用中哪里会用到。

访问 http://localhost/category/id/1111 则最终匹配到规则H,因为以上规则都不匹配,这个时候nginx转发请求给后端应用服务器,比如FastCGI(php),tomcat(jsp),nginx作为方向代理服务器存在。

4. 常用规则

#直接匹配网站根,通过域名访问网站首页比较频繁,使用这个会加速处理,官网如是说。
#这里是直接转发给后端应用服务器了,也可以是一个静态首页
# 第一个必选规则
location = / {
proxy_pass http://tomcat:8080/index
}

# 第二个必选规则是处理静态文件请求,这是nginx作为http服务器的强项
# 有两种配置模式,目录匹配或后缀匹配,任选其一或搭配使用
location ^~ /static/ { //以xx开头
root /webroot/static/;
}
location ~* \.(gif|jpg|jpeg|png|css|js|ico)$ { //以xx结尾
root /webroot/res/;
}

#第三个规则就是通用规则,用来转发动态请求到后端应用服务器
#非静态文件请求就默认是动态请求,自己根据实际把握
location / {
proxy_pass http://tomcat:8080/
}

4. 静态资源服务配置

1,将静态资源复制到home的www目录下
2,在配置文件中进行配置

server {
        listen       88;
        server_name  localhost;

        location / {
            root   /home/www;
            index  index.html index.htm;
        }
        location /static{
          #root  /home;
          alias  /home/xyao

                }
}

5. root 与 alias

  1. 假如服务器路径为:/home/xyao/files/img/face.png

root 路径完全匹配访问
配置的时候为:

location /xyao {
    root /home
}

用户访问的时候请求为:url:port/xyao/files/img/face.png

  1. alias 可以为你的路径做一个别名,对用户透明

配置的时候为:

location /hello {
    alias /home/xyao
}

用户访问的时候请求为:url:port/hello/files/img/face.png,如此相当于为目录xyao做一个自定义的别名。

五、Nginx配置Https

1. Http与Https的区别

HTTP:是互联网上应用最为广泛的一种网络协议,是一个客户端和服务器端请求和应答的标准(TCP),用于从WWW服务器传输超文本到本地浏览器的传输协议,它可以使浏览器更加高效,使网络传输减少。

HTTPS:是以安全为目标的HTTP通道,简单讲是HTTP的安全版,即HTTP下加入SSL层,HTTPS的安全基础是SSL,因此加密的详细内容就需要SSL。HTTPS协议的主要作用可以分为两种:一种是建立一个信息安全通道,来保证数据传输的安全;另一种就是确认网站的真实性。

HTTPS和HTTP的区别主要如下:
1、https协议需要到ca申请证书,一般免费证书较少,因而需要一定费用。
2、http是超文本传输协议,信息是明文传输,https则是具有安全性的ssl加密传输协议。
3、http和https使用的是完全不同的连接方式,用的端口也不一样,前者是80,后者是443。
4、http的连接很简单,是无状态的;HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,比http协议安全。

2. 使用openssl生成证书

1,openssl是目前最流行的SSL密码库工具,其提供了一个通用、健壮、功能完备的工具套件,用以支持SSL/TLS协议的实现。比如生成到:/usr/local/ssl

openssl req -x509 -nodes -days 36500 -newkey rsa:2048 -keyout /usr/local/ssl/nginx.key -out /usr/local/ssl/nginx.crt

2,生成过程:

[root@iZwz9hmxhr8nh72bwa5lbxZ ~]# openssl req -x509 -nodes -days 36500 -newkey rsa:2048 -keyout /usr/local/ssl/nginx.key -out /usr/local/ssl/nginx.crt
Generating a 2048 bit RSA private key
...............................................................................+    ++
...............+++
writing new private key to '/usr/local/ssl/nginx.key'
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [XX]:CN
State or Province Name (full name) []:beijing
Locality Name (eg, city) [Default City]:beijing
Organization Name (eg, company) [Default Company Ltd]:xxxx
Organizational Unit Name (eg, section) []:xxxx
Common Name (eg, your name or your server's hostname) []:xxxx(一般是域名)
Email Address []:xxxx@xxxx.com

[root@iZwz9hmxhr8nh72bwa5lbxZ ~]# ll
total 8
-rw-r--r--. 1 root root 1391 Apr 21 13:29 nginx.crt
-rw-r--r--. 1 root root 1704 Apr 21 13:29 nginx.key

3. Nginx安装http_ssl_module模块

Nginx如果未开启SSL模块,配置Https时提示错误。

nginx: [emerg] the "ssl" parameter requires ngx_http_ssl_module in /usr/local/nginx/conf/nginx.conf:xxx

nginx缺少http_ssl_module模块,编译安装的时候带上—with-http_ssl_module配置就行了。
本场景是服务器已经安装过nginx,但是未安装http_ssl_module。

  1. 安装ssl插件

    yum -y install openssl openssl-devel
    
  2. 进入到源码包,如:

    cd /root/nginx-1.10.3
    
  3. configure:配置ssl

    ./configure --prefix=/usr/local/nginx --with-http_stub_status_module --with-http_ssl_module
    
  4. make:

    make
    
  5. 不需要执行make install,否则就覆盖安装了。


  6. 备份原有的nginx,(可选)如:

    cp /usr/local/nginx/sbin/nginx /usr/local/nginx/sbin/nginx_bak
    
  7. 然后将刚刚编译好的nginx覆盖掉原有的nginx(nginx需要停止)

    cp ./objs/nginx /usr/local/nginx/sbin/
    
  8. 查看安装情况:

    /usr/local/nginx/sbin/nginx -V
    

4. nginx配置https

  1. 配置https服务器 ``` server { listen 443 ssl; server_name www.yourdomain.com; ssl_certificate /usr/local/ssl/nginx.crt; ssl_certificate_key /usr/local/ssl/nginx.key; ssl_session_cache shared:SSL:1m; ssl_session_timeout 5m;

    禁止在header中出现服务器版本,防止黑客利用版本漏洞攻击

    server_tokens off;

    如果是全站 HTTPS 并且不考虑 HTTP 的话,可以加入 HSTS 告诉你的浏览器本网站全站加密,并且强制用 HTTPS 访问

    fastcgi_param HTTPS on; fastcgi_param HTTP_SCHEME https; access_log /usr/local/nginx/logs/httpsaccess.log; location / {
         root   html;
         index  index.html index.htm;
     }
    
    }

2. 先检验配置的对不对:

/usr/local/nginx/sbin/nginx -t

nginx: the configuration file /usr/local/nginx/conf/nginx.conf syntax is ok

nginx: configuration file /usr/local/nginx/conf/nginx.conf test is successful



3,使用http跳转https

server { listen 80; server_name www.yourdomain.com; rewrite ^(.*) https://$server_name$1 permanent; #http 跳转 https }



<a name="zV69t"></a>
## 5. 使用Https访问

1. 打开地址栏使用https访问
```http
https://192.168.174.133/
  1. 由于是证书是自己的创建的所以不安全

image.png

  1. 注意打开443端口
    firewall-cmd --zone=public --add-port=443/tcp
    

6. 专业证书的申请

image.png
image.png
image.png
image.png

Nginx配置
注意最后配置的时候,域名要和申请的域名保持一致

server {
    listen 443;
    server_name bjubi.com; // 你的域名
    ssl on;
    root /var/www/bjubi.com; // 前台文件存放文件夹,可改成别的
    index index.html index.htm;// 上面配置的文件夹里面的index.html
    ssl_certificate  cert/214292799730473.pem;// 改成你的证书的名字
    ssl_certificate_key cert/214292799730473.key;// 你的证书的名字
    ssl_session_timeout 5m;
    ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_prefer_server_ciphers on;
    location / {
        index index.html index.htm;
    }
}
server {
    listen 80;
    server_name bjubi.com;// 你的域名
    rewrite ^(.*)$ https://$host$1 permanent;// 把http的域名请求转成https
}

六、将nginx作为文件服务器

image.png

1. 安装vsftp

[root@bogon ~]# yum -y install vsftpd

1. 安装vsftpd组件

安装完后,有/etc/vsftpd/vsftpd.conf 文件,是vsftp的配置文件。

启动ftp服务器
Centos7.0启动方式: systemctl start vsftpd.service
Centos6.x 启动方式: service vsftpd start

查看ftp服务器启动的情况
service vsftpd status

2. 安装ftp的客户端(部署用)

image.png
在防火墙中放行21端口(21是ftp的端口,22是sftp的端口)
firewall-cmd —zone=public —add-port=21/tcp

firewall-cmd —list-ports (查看防火墙,放行的端口)
image.png

打开客户端的的主动模式
可以直接使用匿名访问进行测试
image.png

开发匿名访问时不安全的,可以关闭

3. 关闭匿名访问

修改/etc/vsftpd/vsftpd.conf文件:
image.png
重启ftp服务:

service vsftpd restart

4. 添加一个Linux用户

此用户就是用来登录ftp服务器用的。
[root@bogon ~]# useradd ftpuser
这样一个用户建完,可以用这个登录,记得用普通登录不要用匿名了。登录后默认的路径为 /home/ftpuser.

5. 给ftp用户添加密码。

[root@bogon ~]# passwd ftpuser
输入两次密码后修改密码。

2. 配置nginx的图片路径地址

image.png

3. 设置访问ftp路径的用户

image.png

4. Ftp传送文件(代码)

1,导入相关的依赖

<dependency>
    <groupId>org.apache.camel</groupId>
    <artifactId>camel-ftp</artifactId>
    <version>2.13.2</version>
</dependency>

2,实现FtpUtil类

package com.learn.util;


import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPReply;

/**
 * ftp上传下载工具类
 * <p>Title: FtpUtil</p>
 * <p>Description: </p>
 */
public class FtpUtil {

   /** 
    * Description: 向FTP服务器上传文件 
    * @param host FTP服务器hostname 
    * @param port FTP服务器端口 
    * @param username FTP登录账号 
    * @param password FTP登录密码 
    * @param basePath FTP服务器基础目录
    * @param filePath FTP服务器文件存放路径。例如分日期存放:/2015/01/01。文件的路径为basePath+filePath
    * @param filename 上传到FTP服务器上的文件名 
    * @param input 输入流 
    * @return 成功返回true,否则返回false 
    */  
   public static boolean uploadFile(String host, int port, String username, String password, String basePath,
         String filePath, String filename, InputStream input) {
      boolean result = false;
      FTPClient ftp = new FTPClient();
      try {
         int reply;
         ftp.connect(host, port);// 连接FTP服务器
         // 如果采用默认端口,可以使用ftp.connect(host)的方式直接连接FTP服务器
         ftp.login(username, password);// 登录
         reply = ftp.getReplyCode();
         if (!FTPReply.isPositiveCompletion(reply)) {
            ftp.disconnect();
            return result;
         }
         //切换到上传目录
         if (!ftp.changeWorkingDirectory(basePath+filePath)) {
            //如果目录不存在创建目录
            String[] dirs = filePath.split("/");
            String tempPath = basePath;
            for (String dir : dirs) {
               if (null == dir || "".equals(dir)) continue;
               tempPath += "/" + dir;
               if (!ftp.changeWorkingDirectory(tempPath)) {
                  if (!ftp.makeDirectory(tempPath)) {
                     return result;
                  } else {
                     ftp.changeWorkingDirectory(tempPath);
                  }
               }
            }
         }
         //设置上传文件的类型为二进制类型
         ftp.setFileType(FTP.BINARY_FILE_TYPE);
         //上传文件
         if (!ftp.storeFile(filename, input)) {
            return result;
         }
         input.close();
         ftp.logout();
         result = true;
      } catch (IOException e) {
         e.printStackTrace();
      } finally {
         if (ftp.isConnected()) {
            try {
               ftp.disconnect();
            } catch (IOException ioe) {
            }
         }
      }
      return result;
   }

   /** 
    * Description: 从FTP服务器下载文件 
    * @param host FTP服务器hostname 
    * @param port FTP服务器端口 
    * @param username FTP登录账号 
    * @param password FTP登录密码 
    * @param remotePath FTP服务器上的相对路径 
    * @param fileName 要下载的文件名 
    * @param localPath 下载后保存到本地的路径 
    * @return 
    */  
   public static boolean downloadFile(String host, int port, String username, String password, String remotePath,
         String fileName, String localPath) {
      boolean result = false;
      FTPClient ftp = new FTPClient();
      try {
         int reply;
         ftp.connect(host, port);
         // 如果采用默认端口,可以使用ftp.connect(host)的方式直接连接FTP服务器
         ftp.login(username, password);// 登录
         reply = ftp.getReplyCode();
         if (!FTPReply.isPositiveCompletion(reply)) {
            ftp.disconnect();
            return result;
         }
         ftp.changeWorkingDirectory(remotePath);// 转移到FTP服务器目录
         FTPFile[] fs = ftp.listFiles();
         for (FTPFile ff : fs) {
            if (ff.getName().equals(fileName)) {
               File localFile = new File(localPath + "/" + ff.getName());

               OutputStream is = new FileOutputStream(localFile);
               ftp.retrieveFile(ff.getName(), is);
               is.close();
            }
         }

         ftp.logout();
         result = true;
      } catch (IOException e) {
         e.printStackTrace();
      } finally {
         if (ftp.isConnected()) {
            try {
               ftp.disconnect();
            } catch (IOException ioe) {
            }
         }
      }
      return result;
   }

   public static void main(String[] args) {
      try {  
           FileInputStream in=new FileInputStream(new File("F:\\upload\\a2.png"));  
           boolean flag = uploadFile("192.168.59.144", 21, "root", "123456", "/home/ftpuser","/www/images/", "2.png", in);  
           System.out.println(flag);  
       } catch (FileNotFoundException e) {  
           e.printStackTrace();  
       }  
   }
}