web框架概览

1)网络框架及MVC架构

​ MVC是软件工程中的一种软件架构设计模式,MVC把web应用系统分为如下3个基本部分:模型、视图、控制器,它们各自处理着自己的任务。几乎所有的Python全栈网络框架强制或引导开发者使用MVC架构开发Web应用。

注:全栈网络框架,是指除了封装网络和线程操作,还提供http栈,数据库的读写管理,HTML模板引擎等一系列功能的网络框架。

  • MVC结构实现:创建一个作为模型的Student模型对象。StudentView是一个把学生详细信息输出到控制台的视图类,StudentController是负责存储数据到Student对象中的控制类,并相应地更新视图StudentView。MVCPatternDemo是使用StudentController来演示MVC模式用法的演示类。

  • 模型(Model),用于封装与应用程序业务逻辑相关数据的处理,Model层是Web应用程序中处理应用程序的数据逻辑部分。换言之,模型表示企业数据和业务规则(大白话就是后端接口,用于业务处理)。

  • 视图(View),负责数据的展示与呈现。

  • 控制器(Controller),负责接受用户的输入并调用模型和视图去完成用户的需求,控制器本身不输出任何东西和做任何处理。它只是接收请求并决定调用哪个模型构件去处理请求,然后再确定用哪个视图来显示返回的数据。(可以看做是View的反向实现)

    当前的主流服务器都实现了主流语言的可调用接口标准,有如下标准。

    1. CGI(Common Gateway Interface),CGI规范允许Web服务器执行外部程序,并将它们的输出发送给Wb服务器,CGI将Web的一组简单的静态超媒体文档变成一个完整的新交互式媒体。

    2. ISAPI(Internet Server Application Program Interface)是微软提供的一套面向Web服务的API接口,它能实现CGI提供的全部功能,并在此基础上进行了扩展(比如提供了过滤应用程序的接口)。

    3. WSGI(Web Server Gateway Interface)是一套专门为Python语言制定的网络服务器标准接口。Python Web框架均以WSGI为基础构建。

    ​ 一般来说,最简单的服务器端程序可以是直接读取某文件或返回固定的网页内容;稍复杂一些的服务端程序需要处理客户端通过HTTP、URL、HTML传入的参数、动态的执行逻辑代码、在数据库或者缓存中读写数据等一系列操作,才能最终生成调用结果。

    ​ Web服务器是连接用户浏览器和Python服务器端程序的中间节点,在网站建立的过程中有着重要的作用。目前主流的Web服务器包括Nginx、Apache、lighthttpd、IIS等。Python服务端程序在Linux使用最广泛的是Nginx。

    2)WSGI接口

    ​ WSGI是将Python服务器端程序连接到Web服务器的通用协议。由于WSGI的通用性,出现了独立的WSGI程序,例如uWSGI和Apache的mod_wsgi。

    ​ 由上图可知,WSGI的接口可分为两种:一个是与Web服务器接口,另一个是与服务器端程序的接口。WSGI Server与Web服务器的接口包括uwsgi、fastcgi等,服务器端程序的开发者无需学习此部分的详细内容,相反更应该关注WSGI与服务器端程序的接口。

    ​ 虽然WSGI的设计目标是连接标准的Web服务器(Nginx,apache)与服务器端程序,但WSGI Server本身也可作为Web服务器运行(但WSGI性能方面不佳,WSGI Server一般只用于测试使用,不能用于正式运行)。

Linux+Nginx+uWSGI配 置

​ Nginx是Python在Linux环境下的首选Web服务器之一(通常作为高性能http和反向代理服务器,广泛运用于天猫、美团、腾讯等大厂),以下演示在Ubuntu Linux中演示Nginx的安装与配置方法。

1) 安装Nginx

在Ubuntu Linux中可以通过如下命令安装Nginx:

sudo apt-get install nginx

安装程序把Nginx以服务的形式安装在系统中,相关的程序及文件路径如下。

  • 程序文件:放在/usr/sbin/nginx目录中。
  • 全局配置文件:/etc/nginx/nginx.conf。
  • 访问日志文件:/var/log/nginx/access.log。
  • 错误日志文件:/var/log/nginx/err.log。
  • 站点配置文件:/etc/nginx/sites-enabled/default。

安装好了,用如下命令启动Nginx服务器:

sudo service nginx start

停止Nginx服务器:

sudo service nginx stop

查看Nginx服务的状态:

sudo service nginx status

重启Nginx服务器:

sudo service nginx restart

2) Nginx配置文件

​ Nginx安装后会以默认方式启动,在开发调试的过程中可能需要调整Nginx的运行参数,这些运行参数会通过全局配置文件(nginx.conf)和站点配置文件(sites-enabled)进行设置,对全局配置文件(/etc/nginx/nginx.conf)中的关键可设置参数解析如下:

 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
user www-data;								 ##定义运行Nginx的用户
worker_processes 4;							 ##Nginx进程数,应设置与系统CPU数量相等的数值
worker_rlimit_nofile 65535;                  ##每个Nginx进程可以打开的最大文件数
events{
    worker_connections 768;                  ##每个Nginx进程允许的最大客户端连接数
    
    #在Nginx接到一个新连接通知后调用accept()来接受尽量多的连接
    multi_accept off;
}
http{
    ##
    # Basic Settings
    ##
    sendfile on;							  ##是否允许文件上传
    client_header_buffer_size 32K;			  ##上传文件大小限制
    tcp_nopush on;							  ##防止网络拥塞
    tcp_nodelay on;                           ##防止网络拥塞
    keepalive_timeout 65;					  ##允许客户端长连接最大秒数
    
    ##Nginx散列表大小。本值越大,占用的内存空间越大,但路由速度很快
    types_hash_max_size 2048;
    
    access_log /var/log/nginx/access.log;	  ##访问日志文件路径名
    error_log  /var/log/nginx/error.log;      ##错误日志文件路径名
    
    ## 如下两条用include命令加载站点配置文件
    include /etc/nginx/conf.d/*.conf;
    include /etc/ngigx/sites-enabled/*; 
}

​ 在每个Nginx服务器中可以运行多个Web站点。每个站点的配置通过站点配置文件设置。每个站点应该以一个单独的配置文件存放在/etc/nginx/sites-enabled目录中,默认站点的配置文件名为/etc/nginx/sites-default,对其中关键内容的解析如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
server{
    ##配置站点监听的端口
    listen 80;
    
    root /usr/share/nginx/html;				  ##配置HTTP根页面目录
    index index.html index.htm;				  ##配置HTTP根目录中的默认页面
    
    #站点监听的IP地址,默认的localhost只可用于本机访问,一般需要将其更改为真实IP
    sever_name localhost;
    
    ##location用于配置URL的转发接口
    location /user/{
        ##此处配置http://server_name/user/的转发地址
        proxy_pass http://127.0.0.1:8080;
    }
    
    #错误页面配置,如下配置定义HTTP 404错误的显示页面 /404.html
    error_page 404 /404.html;
}

3) 安装uWSGI及配置

​ uWSGI是WSGI在Linux中的一种实现,这样开发者无需自己编写WSGI Server。使用pip命令可以直接安装uWSGI。

pip install uwsgi

 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
wjq@Ubuntu:~/TornadoWork/tornado_0/temp/cha5$ uwsgi --http-socket :9090 --plugin python --wsgi-file webapp.py
open("./python_plugin.so"): No such file or directory [core/utils.c line 3724]
!!! UNABLE to load uWSGI plugin: ./python_plugin.so: cannot open shared object file: No such file or directory !!!
*** Starting uWSGI 2.0.18 (64bit) on [Sat Mar 16 11:23:32 2019] ***
compiled with version: 4.8.4 on 16 March 2019 02:33:42
os: Linux-4.4.0-124-generic #148~14.04.1-Ubuntu SMP Thu May 3 07:26:53 UTC 2018
nodename: Ubuntu
machine: x86_64
clock source: unix
detected number of CPU cores: 2
current working directory: /home/wjq/TornadoWork/tornado_0/temp/cha5
detected binary path: /usr/local/bin/uwsgi
!!! no internal routing support, rebuild with pcre support !!!
*** WARNING: you are running uWSGI without its master process manager ***
your processes number limit is 11929
your memory page size is 4096 bytes
detected max file descriptor number: 1024
lock engine: pthread robust mutexes
thunder lock: disabled (you can enable it with --thunder-lock)
uwsgi socket 0 bound to TCP address :9090 fd 3
Python version: 2.7.12 (default, Jul 18 2016, 15:07:05)  [GCC 4.8.4]
*** Python threads support is disabled. You can enable it with --enable-threads ***
Python main interpreter initialized at 0x1a33880
your server socket listen backlog is limited to 100 connections
your mercy for graceful operations on workers is 60 seconds
mapped 72920 bytes (71 KB) for 1 cores
*** Operational MODE: single process ***
WSGI app 0 (mountpoint='') ready in 0 seconds on interpreter 0x1a33880 pid: 4554 (default app)
*** uWSGI is running in multiple interpreter mode ***
spawned uWSGI worker 1 (and the only) (pid: 4554, cores: 1)
[pid: 4554|app: 0|req: 1/1] 59.68.29.48 () {32 vars in 590 bytes} [Sat Mar 16 11:47:29 2019] GET / => generated 20 bytes in 0 msecs (HTTP/1.1 200) 1 headers in 43 bytes (0 switches on core 0)
[pid: 4554|app: 0|req: 2/2] 59.68.29.48 () {32 vars in 571 bytes} [Sat Mar 16 11:47:30 2019] GET /favicon.ico => generated 20 bytes in 0 msecs (HTTP/1.1 200) 1 headers in 43 bytes (0 switches on core 0)
[pid: 4554|app: 0|req: 3/3] 59.68.29.48 () {32 vars in 571 bytes} [Sat Mar 16 11:47:38 2019] GET /favicon.ico => generated 20 bytes in 0 msecs (HTTP/1.1 200) 1 headers in 43 bytes (0 switches on core 0)

uwsgi --http-socket :9090 --plugin python --wsgi-file webapp.py

​ 启动时用-http参数指定了监听端口,用–wsgi-file指定了服务端的程序名。如上所示,uWSGI在启动的过程中会输出系统的一些环境信息:服务器名、进程数限制、服务器硬件配置、最大文件句柄数等。除了在uWSGI 启动命令行提供配置参数,uWSGI 还允许通过一个配置文件设置这些配置参数,比如可以编写如下配置文件,保存在文件名uwsgi.ini中:

1
2
3
[uwsgi]
http = 9090
wsgi-file = webapp.py

​ 启动uWSGI时直接指定配置文件即可。

uwsgi uwsgi.ini

除了http和wsgi-file参数,uWSGI还有许多其他参数,常用的如下。

  • socket: 以WSGI的Socket方式运行,并指定连接地址和端口。该Socket接口是uWSGI与其他Web服务器(Nginx/Apache)等进行对接的方式。

  • chdir: 指定uWSGI 启动后的当前目录。

  • processes: 指定启动服务器端程序的进程数。

  • threads: 指定每个服务器端程序的线程数。即服务器端的总线程数为processes * threads。

  • uid: 指定运行uWSGI的Linux用户id。

    举例,如下配置文件用于以Socket方式启动一个uWSGI服务器,并配置了进程和线程数。

1
2
3
4
5
[uwsgi]
socket = 127.0.0.1: 3011
wsgi-file = webapp.py
processes = 4
threads = 3

4) 集成Nginx与uWSGI

​ 直接通过在站点配置文件中为location配置uwsgi_pass,即可将Nginx与uWSGI集成,建立一个基于Nginx+Python的正式站点。针对如下uWSGI接口有:

1
2
3
[uwsgi]
socket = 127.0.0.1: 3011
wsgi_file = webapp.py

​ Nginx的站点配置文件为:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
server{
    listen 80;
}
## 此处改为服务器的真实IP
	server_name 121.12.134.11;
location /{
    ## 此处IP与Port配置必须与uwsgi接口中参数相同
    uwsgi_pass http://127.0.0.1:3011;
}
'''
可以为一个uWSGI配置多个Nginx Server和location,这样就可以实现多域名访问同一个python程序。
'''

建立安全的HTTPS网站

​ 大多数的HTTP站点的协议与数据以明文方式在网络上传输,而HTTPS(HyperText Transfer Protocol over Secure Socket Layer )是以安全为目标的HTTP通道,即在HTTP下加入SSL层,通过SSL达到数据加密及身份认证的功能。目前大多数银行、证券、交通的网站均以HTTPS方式构建。

​ OpenSSL是一个强大的免费Socket层密码库,蕴含了主要的密码算法、常用的密钥和证书封装管理功能以及SSL协议。目前大多数网站通过OpenSSL工具搭建HTTPS站点,其步骤如下。

  • 在服务器中安装OpenSSL工具包。
  • 生成SSL密钥和证书。
  • 将证书配置到Web服务器。
  • 在客户端安装CA证书。

​ 如下记录在Ubuntu 14.04.5 LTS (GNU/Linux 4.4.0-124-generic x86_64)下使用OpenSSL的方法,以及Nginx在Linux下的证书配置方式。类似Linux其他发行版、Windows方法类似。

1)在服务器中安装OpenSSL工具包

​ 通过如下两条命令安装OpenSSL:

1
2
#sudo apt-get install openssl
#sudo apt-get install libssl-dev 
命令运行成功后,OpenSSL命令和配置文件将被安装到Linux系统目录中。
  • OpenSSL命令:/usr/bin/openssl。

  • 配置文件:/usr/lib/ssl/*。

    2)生成SSL密钥和证书

    1
    
    通过如下步骤生成CA证书ca.crt、服务器密钥文件server.key和服务器证书server.crt:
    
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
#生成CA密钥
openssl genrsa -out ca.key 2048

#生成CA证书,days参数以天为单位设置证书的有效期。在本过程中会要求输入证书的所在地、公司名、站点名等
openssl req -x509 -new -nodes -key ca.key -days 365 -out ca.crt

#生成服务器证书RSA的密钥对
openssl genrsa -out server.key 2048

#生成服务器端证书ca.crt
openssl x509 -req -in server.csr -CA ca.crt -CAKey ca.key -CAcreateserial -out server.crt -days 365

​ 上述命令生成服务器端证书时,需要在Common Name(CN)字段中如实输入站点的访问地址。即设若要访问www.abc.com进行访问,则必须定义CN=www.abc.com;如果通过IP地址访问,则需设置CN为具体的IP地址。

3)配置Nginx HTTPS服务器

​ 在站点配置文件/etc/nginx/sites-enabled/default中添加如下server段,可以定义一个基于HTTPS的接口,该接口的服务器端程序仍旧为uWSGI接口127.0.0.1:3011。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
server{
    listen					443;			#HTTPS服务端口
    server_name				0.0.0.0;	    #本机上的所有IP地址
    ssl						on;					#
    ssl_certificate			/etc/nginx/ssl/server.crt;
    ssl_certificate_key		/etc/nginx/ssl/server.key;

location \ {
    uwsgi_pass http://127.0.0.1:3011;
	}
}

​ 其中需要注意的参数ssl_certificate和ssl_certificate_key需要分别指定生成的服务器证书和服务器密钥的全路径文件名。到此,我们就可以使用浏览器访问服务器的443端口进行HTTPS加密通信了。