社区所有版块导航
Python
python开源   Django   Python   DjangoApp   pycharm  
DATA
docker   Elasticsearch  
aigc
aigc   chatgpt  
WEB开发
linux   MongoDB   Redis   DATABASE   NGINX   其他Web框架   web工具   zookeeper   tornado   NoSql   Bootstrap   js   peewee   Git   bottle   IE   MQ   Jquery  
机器学习
机器学习算法  
Python88.com
反馈   公告   社区推广  
产品
短视频  
印度
印度  
Py学习  »  NGINX

Nginx实战部署常用功能演示(超详细版),绝对给力~~~

dotNET跨平台 • 2 年前 • 332 次点击  

前言

上次分享了一些开发过程中常用的功能,但如果到真实环境中,其实还需要一些额外的配置,比如说跨域、缓存、配置SSL证书、高可用等,老规矩,还是挑几个平时比较常用的进行演示分享。上篇详见Nginx超详细常用功能演示,够用啦~~~

正文

1. 跨域

跨域是因为浏览器同源策略的保护,不能直接执行或请求其他站点的脚本和数据;一般我们认为的同源就是指协议、域名、端口都相同,否则就不是同源。

现在前后端分离开发已经很普遍了,跨域问题肯定少不了,但解决的方式也很多,比如JsonP、后端添加相关请求头等;很多时候,不想改动代码,如果用到nginx做代理服务器,那就可以轻松配置解决跨域问题。

1.1 环境准备

需要准备两个项目,一个前端项目发布在80端口上,一个API项目发布在5000端口上,这里需要在阿里云的安全组中将这两个端口开放;

  • API项目环境(对外是5000端口)

    API接口还是使用上次演示的项目,很简单,过程我就不再重复上图啦,直接来两张重要的;

    配置nginx反向代理,然后运行看效果:

  • 前端环境(对外是80端口)

    前端页面(kuayu.html)

    html>
    <html>
    <head>
      <title>跨域测试title>
      <script src="http://code.jquery.com/jquery-2.1.1.min.js">script>
      <script type="text/javascript">
          
    .rea dy(function()¨E123E// (document).ready(funct ion()¨E123E//,("#b01").click(function() {
                  // 请求数据
                  htmlobj=
    .ajax(¨E123Eurl:"http://47.113.204.41:5000/wea therforecast/getport",as ync:false¨E125E);//div .ajax(¨E123Eurl:"http://47.113.20 4.41:5000/weatherforecast /getport",async:false¨E125E); //div中("#myDiv").html(htmlobj.responseText);
            });
          });
      
    script>
    head>
    <body>
      <h2>获取结果h2>
      <div id="myDiv">结果显示div>
      <button id="b01" type="button"> GetPortbutton>
    body>
    html>

    将kuayu.html通过xFtp拷贝到服务器上,对应的static目录是自己创建的,如下图:

  • nginx配置及运行测试

    配置nginx,在原有配置文件中再新增一个server块,如下配置:

    运行测试:

    跨域问题出现了,现在前后端都不想改代码,要干架吗?nginx说:和谐,一定要和谐~~~

1.2 配置跨域及运行

在API的server中进行跨域配置,如下:

重启nginx之后,再测试,看看搞定了没?

2. 配置SSL证书

现在的站点几乎都是https了,所以这个功能必须要实操一把;为了更符合真实线上场景,我特意准备了域名和证书,真真实实在阿里云服务器上演示;这里需要登录到阿里云上购买域名,然后根据域名申请免费的SSL证书,最后进行配置使用,详情如下:

2.1 准备域名

这里我注册了一个域名为:codezyq.cn;下面先说说注册域名的流程:

  • 登录阿里云,找到域名注册入口

  • 进入到一个页面,然后输入需要注册的域名

  • 然后就出现搜索结果,如果被注册就会提示,可以选择其他类型或更换域名

  • 买了域名之后,需要进行实名认证,个人上传身份证就完事啦,一会就实名完成; 完成之后就需要配置域名解析,即解析到自己的云服务器上,后续通过域名才可以访问;

  • 测试是否能解析成功,直接在自己电脑上ping一下域名,看看是否解析到指定IP即可,简单直接;这样域名就可以用啦~~~

2.2 准备证书

免费证书这块的申请需要用到买的域名,大概步骤如下:

  • 领取免费证书数量(20个)

  • 进入SSL证书(应用安全页面)进行证书创建

  • 进行证书申请,即绑定域名

    填写申请信息,如下:

    这里一般填完申请信息,后续验证那块直接过也能签发,列表状态如下:

  • 签发完成之后,下载对应服务器的证书即可,点击下载选择

    直接下载下来一会配置使用。

2.3 nginx配置证书
  • 检查环境

    检查端口是否可访问

    https需要443端口,所以在阿里云中将443端口加入到安全组中,如下图:

    另外还需要查看云服务器的防火墙有没有开放对应的端口,如下命令:

    # 查看防火墙端口开放情况
    firewall-cmd --list-all
    public
    target: default
    icmp-block-inversion: no
    interfaces: 
    sources: 
    services: dhcpv6-client ssh
    # 显示的结果没有开放443端口
    ports: 80/tcp 22/tcp 5000/tcp 3306/tcp 6379/tcp  

    # 将443端口加入到里面
    firewall-cmd --zone=public --add-port=443/tcp --permanent
    # 重新加载
    firewall-cmd --reload
    # 再看防火墙端口开放情况
    firewall-cmd --list-all
    public
    target: default
    icmp-block-inversion: no
    interfaces: 
    sources: 
    services: dhcpv6-client ssh
    # 443端口加入进来了
    ports: 80/tcp 22/tcp 5000/tcp 3306/tcp 6379/tcp 8080/tcp 443/tcp 

    检查nginx中是否包含http_ssl_module模块

    在配置证书之前需要检查一下nginx中是否已经包含http_ssl_module:

    如果没有就算配置了也不能用,如下:

  • 为nginx加上http_ssl_module

    需要下载一个源码进行引入,这里还是使用版本1.18.0,具体步骤如下:

    第一步,先准备环境,比如支持编译、openssl等,执行以下命令:

    
    
    
        
    # 安装对应的包
    yum -y install gcc openssl openssl-devel pcre-devel zlib zlib-devel

    第二步,下载对应版本源码到usr/local/src中,并进行解压,执行以下命令

    # 下载指定版本nginx包
    wget http://nginx.org/download/nginx-1.18.0.tar.gz
    # 解压
    tar -zxvf nginx-1.18.0.tar.gz

    第三步,进入解压目录中,配置http_ssl_module,命令如下:

    # 进入解压目录
    cd nginx-1.18.0
    # 加入http_ssl_module
    ./configure --prefix=/usr/local/nginx --with-http_ssl_module

    第四步,编译,在解压目录中直接执行make命令即可

    # 执行make命令,在当前目录就会添加新目录objs
    make
    # 如果是新安装nginx,执行以下命令
    # make&make install

    如果没报错,就编译出最新的啦;这里我在实操的时候,先执行的./configure 配置命令,然后再执行第一步的命令,所以导致make的时候老是不成功,这里解决方案是在添加http_ssl_module模块时,同时指定了openssl源码路径(直接下载即可),然后再执行make命令就成功了。命令如下:

    # 指定openssl源码路径 需要下载
    ./configure --prefix=/usr/local/nginx --with-openssl=/usr/src/openssl-1.1.1d --with-http_ssl_module
    # 再执行make命令编译
    make

    第五步,将编译出来新的nginx文件替换原有的nginx文件,操作如下:

  • 在nginx配置SSL的支持

    还记得获取下载证书的时候吗,下载界面那有一个帮助操作,点击就有nginx配置SSL证书的详细步骤,如下图:

    这里演示配置的内容如下(新增一个server块,专门配置SSL的):

    server {
         # https 监听的是443端口
         listen       443 ssl;
         # 指定准备好的域名
         server_name  codezyq.cn;
         # 指定证书路径,这里需要把准备好的证书放到此目录
         ssl_certificate      /usr/local/nginx/myssl/codezyq.cn.pem;
         ssl_certificate_key  /usr/local/nginx/myssl/codezyq.cn.key;
         ssl_session_cache    shared:SSL:1m;
         # 超时时间
         ssl_session_timeout 5m;
         # 表示使用的加密套件的类型
         ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;
         # 表示使用的TLS协议的类型
         ssl_protocols TLSv1 TLSv1.1 TLSv1.2; 
         ssl_prefer_server_ciphers on;
         location /www/ {
             root   static;
             index  index.html index.htm;
         }
     }
  • 重启nginx,然后进行https访问对应的连接就可以啦

    注:网站如果没有备案,会被拦截,会导致不能访问,正规站点都是要备案的

3. 防盗链配置

盗链通俗一点的理解就是别人的网站使用自己服务器的资源,比如常见的在一个网站引入其他站点服务器的图片等资源,这样被盗链的服务器带宽等资源就会额外被消耗,在一定程度上会损害被盗链方的利益,所以防盗链是必要的;这里通过nginx简单实现静态资源防盗链的案例,原理很简单,就是判断一下请求源是否被允许。

3.1 准备一个html和图片

将准备的html和图片放在创建的static目录下,如下图:

anti-stealing-link.html内容如下

html>
  <html>
  <head>
      <title>anti-stealing-link  testtitle>
  head>
  <body>
      <h2>使用云服务器上的图片h2>
      
      <img src="http://47.113.204.41/img/test.jpg" alt="">
  body>
html>
3.2 正常配置nginx
server {
        listen       80;
        server_name 47.113.204.41;
        # 针对html访问的匹配规则
        location /www/ {
            root static;
            index index.html index.htm;
        }
        # 针对图片访问的匹配规则
        location /img/ {
            root static;
        }
        charset utf-8;
    }

运行起来看效果:

现在有个需求,只能是云服务器的html才能使用图片,其他引用源都认为是盗链,直接返回403或重写到固定图片。

3.3 轻松配置nginx防盗链

针对img配置如下:

server {
        listen       80;
        server_name 47.113.204.41;
        # 针对html访问的匹配规则
        location /www/ {
            root static;
            index index.html index.htm;
        }
        # 针对图片访问的匹配规则
        location /img/ {
            root static;
            #对源站点的验证,验证IP是否是47.113.204.41
            #可以输入域名,多个空格隔开
            valid_referers 47.113.204.41;
            #非法引入会进入下方判断
            if ($invalid_referer) {
               #这里返回403,也可以rewrite到其他图片
               return 403;
            }
        }
        charset utf-8;
    }

重启nginx,清除缓存再试:

防盗链是不是很简单,也可以通过代码的形式,比如在过滤器或管道中也可以实现,如果没有特殊需求,nginx稍微一配置就能实现,岂不美哉~~~

4. 隐藏版本信息

之前在项目中做渗透测试时,其中有一项问题就是不希望在响应头中体现服务器相关版本,避免在某些版本出现漏洞时,攻击者可以特意针对此版本进行恶意攻击,从而影响系统服务可用性。

现有情况:

页面找不到时:

看看nginx是如何关闭,如下配置:

看效果:

正常访问

找不到报错,版本也没有啦

5. 高可用配置

尽管nginx性能再强,但服务器和网络有很多因素是不可控的,如:网络抖动、网络不通、服务器宕机等情况,都会导致服务不可用(可理解为单点故障),这样的系统体验肯定得不到好评;如果当一个服务器宕机或服务挂掉时,另外一台服务器自动代替宕机服务器提供服务,保证系统的正常运行,这就实现了高可用;这里nginx实现高可用的方式和Redis的主从模式很相似,只是nginx使用的是keepalived来实现高可用集群。

5.1 keepalived简介

keepalived实现高可用的关键思路还是主、备节点的来回切换;

  • 首先需要配置一个VIP(虚拟IP),用于提供访问的接口地址,刚开始是在主节点上的;

  • 当主节点发生故障时,VIP就漂移到备节点,由备节点提供服务;

  • 如果主节点恢复,会通知备节点健康状态,VIP就会漂移到主节点;

由上可见,在keepalive实现高可用时,肯定要有机制选择主备节点,主备之间肯定要互相通知,不然咋知道节点之间的健康状态,所以就使用了VRRP协议,目的就是为了解决静态路由的单点故障。

VRRP协议,全称Virtual Router Redundancy Protocol(虚拟路由冗余协议),利用IP多播的方式实现通信;通过竞选协议机制(根据配置的优先级来竞选)来将路由任务交给某台VRRP路由器,保证服务的连续性;

理论先了解这么多,先来把keepalived安装上,

方式一

执行以下命令可直接安装:

# 安装,这种直接安装完成了,修改配置文件启动即可
yum install-y keepalived
# 启动
systemctl start keepalived.service

这种方式可能会遇到启动keepalived的时候报错,原因可能是服务配置文件(/usr/lib/systemd/system/keepalived.service)指定的keepalived相关目录找不到; 如果文件目录都正常,还报错,我折腾了好久,后来用源码方式进行安装就正常啦~~~

方式二

建议使用源码的形式进行安装,大概步骤如下:

第一步,环境准备




    
# 安装对应的依赖包
yum -y install gcc openssl openssl-devel pcre-devel zlib zlib-devel

第二步,下载并解压源码包

# 在/usr/local/src目录下执行,下载到该目录
wget https://www.keepalived.org/software/keepalived-2.0.18.tar.gz
# 解压
tar -zxvf keepalived-2.0.18.tar.gz

第三步,安装

# 进入到解压出来的目录
cd keepalived-2.0.18
# 编译并安装
./configure && make && make install

第四步,创建启动文件,即将编译出来的文件拷贝到对应的目录下

cp  -a /usr/local/etc/keepalived   /etc/init.d/
cp  -a /usr/local/etc/sysconfig/keepalived    /etc/sysconfig/
cp  -a /usr/local/sbin/keepalived    /usr/sbin/

第五步,创建配置文件

# 先创建配置文件存放的目录
mkdir /etc/keepalived
# 再将创建好的配置文件通过xFtp传到此目录,也可以直接在这里创建

配置文件名为keepalived.conf,内容如下:

! Configuration File for keepalived
global_defs {
       # 每台机器的唯一标识
       router_id 31
}
# vrrp实例,可以配置多个
vrrp_instance VI_1 {
    # 标识为主节点,如果是被节点,就为BACKUP
    state MASTER
    # 网卡名称,通过ip addr 命令可以看到对应网卡,需要哪个就配置哪个就行
    interface enp0s8
    # 路由ID,主、备节点的id要一样
    virtual_router_id 3
    # 优先级,主节点的优先级要大于备节点的优先级
    priority 200
    # 主备心跳检测,间隔时间为1s
    advert_int 1 
    # 认证方式,主备节点要一致
    authentication {
       auth_type PASS
       auth_pass 123456
    }
    virtual_ipaddress {
       # 虚拟IP
       192.168.30.108
    }
}

第六步,启动

# 启动
systemctl start keepalived.service
# 查看虚拟IP情况
ip addr 

查看效果如下,虚拟ip正常在master节点上:

安装完keepalived和nginx之后就可以进行主备演示啦~~~

5.2 主备演示

这里用了两台虚拟机,结构如下:

  • 第一步nginx配置准备

    这里用到的就是nginx默认配置,基本没咋改,如果要了解配置文件详情,点击(Nginx超详细常用功能演示,够用啦~~~)有详细说明。两台虚拟机配置的nginx.conf内容如下:

    #user  nobody;
    worker_processes  1;
    events {
      worker_connections  1024;
    }
    http {
      include       mime.types;
      default_type  application/octet-stream;
      sendfile        on;
      keepalive_timeout  65;
      #gzip  on;
      server {
          # 需要防火墙开放80端口
          listen       80;
          server_name  localhost;
          location / {
              root   html;
              index  index.html index.htm;
          }
          error_page   500 502 503 504  /50x.html;
          location = /50x.html {
              root   html;
          }
      }
    }
  • 第二步准备html

    两台虚拟机中html,用的是nginx默认的index.html(路径:/usr/local/nginx/html),为了方便演示,在index.html中增加了个105和106的显示标注,105机器内容如下,106机器上的html只是把内容中的105改成106即可:

  • 第三步准备两台虚拟机上keepalived配置文件(路径:/etc/keepalived)

    105机器上keepalived.conf内容如下

    ! Configuration File for keepalived
    global_defs {
      # 每台机器不一样
      router_id 31
    }
    #检测nginx服务是否在运行
    vrrp_script chk_nginx {
     #使用脚本检测
     script "/usr/local/src/chk_nginx.sh"
     #脚本执行间隔,每2s检测一次
     interval 2
     #脚本结果导致的优先级变更,检测失败(脚本返回非0)则优先级 -5
     weight -5
     #连续2次检测失败才确定是真失败
     fall 2
     #检测到1次成功就算成功
     rise 1                    
    }

    vrrp_instance VI_1 {
      # vrrp实例,可以配置多个
      state MASTER
      # 网卡名称,通过ip addr 命令可以看到对应网卡,需要哪个就配置哪个就行
      interface enp0s8
      # 路由ID,主、备节点的id要一样
      virtual_router_id 3
      # 优先级,主节点的优先级要大于备节点的优先级
      priority 200
      # 主备心跳检测,间隔时间为1s
      advert_int 1
      # 认证方式,主备节点要一致
      authentication {
            auth_type PASS
            auth_pass 123456
      }
      #执行监控的服务。
      track_script { 
          #引用VRRP脚本,即在 vrrp_script 部分指定的名字。
          chk_nginx                    
       }
      virtual_ipaddress {
          # 虚拟IP
          192.168.30.108
      }
    }

    在/usr/local/src/中准备chk_nginx.sh,keepalived和nginx没有直接关系的,只有通过检查nginx的运行状态来进行高可用服务切换,chk_nginx.sh内容如下:

    然后给这个文件增加执行权限,命令如下:

    chmod +x chk_nginx.sh

    106虚拟机上的步骤和检测脚本chk_nginx.sh都一样,只是keepalived.conf内容稍微有点变动。

    106机器上keepalived.conf内容如下

    ! Configuration File for keepalived
    global_defs {
      # 每台机器上不一样
      router_id 32
    }
    #检测nginx服务是否在运行
    vrrp_script chk_nginx {
     #使用脚本检测
     script "/usr/local/src/chk_nginx.sh"
     #脚本执行间隔,每2s检测一次
     interval 2
     #脚本结果导致的优先级变更,检测失败(脚本返回非0)则优先级 -5
     weight -5
     #连续2次检测失败才确定是真失败
     fall 2
     #检测到1次成功就算成功
     rise 1                    

    vrrp_instance VI_1 {
      # 配置为备节点
      state BACKUP
      # ip addr 查看对应的网卡名称
      interface enp0s8
      virtual_router_id 3
      # 优先级比主节点低
      priority 100
      advert_int 1 
      authentication {
          auth_type PASS
          auth_pass 123456
      }
      #执行监控的服务
      track_script {
          #引用VRRP脚本,即在 vrrp_script 部分指定的名字。
          chk_nginx                    
      }
      virtual_ipaddress {
          # 虚拟IP
          192.168.30.108
      }
    }
  • 第四步分别启动两台虚拟机上的nginx和keepalived,命令如下:

    # 启动nginx
    cd /usr/local/nginx/sbin/
    ./nginx
    # 启动keepalived
    systemctl start keepalived.service
    # 查看keepalived状态,是否运行
    systemctl status keepalived.service

    两台虚拟机都要执行

  • 第五步测试,效果如下:

    直接访问虚拟IP就能访问到主节点的服务啦;现在测试当主节点挂掉时,还会不会正常访问服务,在105机器上执行如下命令:

    # 模拟宕机,停止keepalived
    systemctl stop keepalived.service
    # ip addr 查看虚拟IP已经漂移到备节点上了,在备节点用ip addr 查看

    备节点显示,虚拟IP已经漂移过来啦~

    再用虚拟IP访问,效果如下:

    看见已经切换到106机器上提供服务啦,这样就实现高可用啦;

    那主节点重新恢复,虚拟IP会不会恢复回来继续提供服务呢?

    # 重启keepalived
    systemctl restart keepalived.service
    #ip addr 查看虚拟IP情况,恢复过来啦

    继续用虚拟IP访问服务,又回到主服务啦,如果没有,那可能是浏览器缓存,因为这里用静态html演示,清掉缓存再访问。

5.3 多主多备演示

对于上面的主备模式,只有主节点提供服务,如果主节点不发生故障,备节点服务器就有点资源浪费啦,这个时候多主多备不仅能合理利用资源,还得提供备用服务(根据实际需要配置),形成真正集群提供服务。

这里就演示一下双主双备的配置,思路就是在keepalived增加多个vrrp实例,105机器在vrrp实例VI_1中作为主节点,106机器作为备节点,在vrrp实例VI_2中,105机器作为备节点,106机器作为主节点,这样就形成了互为主备的模式,资源就能很好的利用啦;其他逻辑不变,只是分别在105、106机器上加上的keepalived.conf中加上VI_2实例即可,如下:

105机器上keepalived.conf内容如下:




    
global_defs {
       router_id 31
}
#检测nginx服务是否在运行
vrrp_script chk_nginx {
   #使用脚本检测
   script "/usr/local/src/chk_nginx.sh"
   #脚本执行间隔,每2s检测一次
   interval 2
   #脚本结果导致的优先级变更,检测失败(脚本返回非0)则优先级 -5
   weight -5
   #连续2次检测失败才确定是真失败
   fall 2
   #检测到1次成功就算成功
   rise 1                   
}

vrrp_instance VI_1 {
       state MASTER
       interface enp0s8
       virtual_router_id 3
       priority 200
       advert_int 1 
       authentication {
               auth_type PASS
               auth_pass 123456
       }
       track_script {                      
                chk_nginx                    
        }
       virtual_ipaddress {
               192.168.30.108
       }
}
vrrp_instance VI_2 {
        # VI_1是MASTER,这里就是备节点
       state BACKUP
       interface enp0s8
       # 修改路由编号
       virtual_router_id 5
       # 备节点优先级稍低
       priority 100
       advert_int 1
       authentication {
               auth_type PASS
               auth_pass 123456
       }
       track_script {                      
                chk_nginx                    
        }
       virtual_ipaddress {
                  # 虚拟IP
               192.168.30.109
       }
}

106机器上keepalived.conf内容如下:

global_defs {
       router_id 32
}
#检测nginx服务是否在运行
vrrp_script chk_nginx {
   #使用脚本检测
   script "/usr/local/src/chk_nginx.sh"
   #脚本执行间隔,每2s检测一次
   interval 2
   #脚本结果导致的优先级变更,检测失败(脚本返回非0)则优先级 -5
   weight -5
   #连续2次检测失败才确定是真失败
   fall 2
   #检测到1次成功就算成功
   rise 1                   
}
vrrp_instance VI_1 {
       state BACKUP
       interface enp0s8
       virtual_router_id 3
       priority 100
       advert_int 1 
       authentication {
               auth_type PASS
               auth_pass 123456
       }
        track_script {                      
                chk_nginx                    
        }
       virtual_ipaddress {
               192.168.30.108
       }
}
vrrp_instance VI_2 {
       # 这里是主节点
       state MASTER
       interface enp0s8
       # 这里和105机器上的VI_2中id一致
       virtual_router_id 5
       priority 200
       advert_int 1
       authentication {
               auth_type PASS
               auth_pass 123456
       }
       track_script {                      
                chk_nginx                    
        }
       virtual_ipaddress {
                   # 虚拟IP
               192.168.30.109
       }
}

分别重启两台机器上的keepalived,执行命令如下:

然后分别访问虚拟ip 192.168.30.108 和192.168.30.109,都能提供对应的服务啦,这里不截图了。

总结

开发和生产环境比较常用的功能大概就这么多,后续如果用得多的功能会及时和小伙伴分享哦。

这次主要遇见一些问题,小伙伴可以作为参考,汇总如下:

  • VMware虚拟机网络问题,主机ping不通虚拟机、虚拟机ping不通主机、上不了外网

    这个问题折腾了两个晚上,原因是之前的网络配置有一些问题,然后重新装了虚拟机,但是用单网卡的方式依然没有同时解决上面的问题,最后使用两个网卡的方式解决了;一个网卡使用动态分配,另外一个使用静态IP,信息如下:

  • keepalived启动不起来

    使用yum直接安装的方式,可能会遇到启动不起来的情况,排查了服务里面配置路径,目录都对,依赖包也装了还不行;最后使用源码方式安装没问题。

  • keepalived的虚拟ip主机ping不通

    这也是个棘手的问题,虚拟ip能在主、备机器之间正常漂移,就是主机ping不同虚拟IP,当前解决的措施主要步骤,如下:

    首先注释掉keepalived.conf 中vrrp_strict ,然后重启keepalived;

    如果还不行,就排查防火墙;

    再不行,就清arp缓存

一个被程序搞丑的帅小伙,关注"Code综艺圈",跟我一起学~~~


Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/115335
 
332 次点击