Python 3 web开发

web开发发展历程

在这里插入图片描述
Python有上百种web开发框架,有很多成熟的模块技术,用Python进行web开发,开发效率高,运行速度快。

HTTP协议简介

在web应用中,服务器将网页传给服务器,实质上就是将网页的HTML代码发送给浏览器,让浏览器进行显示。浏览器和服务器之间的传输协议是HTTP,所以:

  1. HTML是一种用于定义网页的文本文档;
  2. HTTP是在网络上传输HTML的协议,用于浏览器和服务器之间的通信

实验环境

Google Chrome浏览器

HTTP内容简介

  1. 打开开发者工具
    在浏览器右上角处单击纵向排列的三个点—更多工具—开发者工具,或者通过快捷键optioncommondI打开:
    在这里插入图片描述
    Elements显示了网页的结构,Network显示浏览器和服务器之间的通信。
  2. 记录浏览器和服务器之间的通信
    确保Network下的小红灯亮着,灯亮即表示Chrome在记录server和browser之间的通信
    在这里插入图片描述
  3. 访问网页
    在地址栏输入在这里插入代码片www.sina.com.cn,查阅浏览器的记录以了解浏览器的工作

Request Headers
首先,定位到Networks的第一条记录,在右侧的Request Headers右边单击view source,查看浏览器发送给服务器的请求:
在这里插入图片描述
GET / HTTP/1.1
GET表示一个读取请求,浏览器请求从服务器获得网页的数据,/表示URL的路径。URL总是以/开头。表示首页。最后的HTTP/1.1表示采用的HTTP协议版本为1.1.目前版本为1.1,但大部分的服务器也支持1.1版本,1.1和1.0版本的区别在,于1.1版本允许多个HTTP请求复用一个TCP连接以加快传输速度
Host: www.sina.com.cn
该行表示请求的域名是www.sina.com.cn。如果一台服务器有多个网站,服务器就需要使用Host来区分浏览器的请求。
Response Headers
同样是本条记录,在右侧的ResponseHeaders右边单击view source,查看服务器返回给浏览器的原始响应数据:
在这里插入图片描述
HTTP响应分为Header和body两个部分,我们看到最重要的几行如下:
HTTP/1.1 302 Moved Temporarily
请求相应的状态,正确的响应应为HTTP/1.1 200 OK,失败的响应有404 Not Found:网页不存在,500 Internal Server Error:服务器内部错误,等等。
Content-Type: text/html
响应的内容,此处为text/html,表示HTML网页,浏览器依据Content-Type来判断响应的内容是网页、图片、视频还是音乐。因此,即便URL是http://example.com/abc.jpg,该内容也不一定是图片。
HTTP响应的body就是HTML源码,我们在开发者工具下点击源码选项就可以在浏览器中查看HTML源码:

在这里插入图片描述
当浏览器读取到新浪首页的HTML源码之后,它会解析HTML,显示页面,然后根据HTML里面的各种链接发送HTTP请求给新浪服务器,获取相应的图片、视频、flash、JavaScript脚本、CSS等资源,最终呈现出一个完整的页面。

HTTP请求

在这里插入图片描述
web采用的HTTP协议使用了非常简单的请求-响应模式,大大简化了开发流程。当我们编写页面是,只需要在HTTP响应中把HTML发送出去,而不需要考虑如何附带图片、视频等内容,浏览器如果需要请求图片和视频等内容,它会发送另一个HTTP请求。因此,一个HTTP请求只处理一个资源。
HTTP协议具备极强的扩展性,虽然浏览器请求的是http://www.sina.com.cn但是新浪在HTML中可以链入其他服务器的资源,如`,从而你将请求压力分散到各个服务器上,并且一个站点可以链接到其他站点,无数个站点互相链接起来,形成了world wide web简称“www"。

HTTP格式

每个HTTP请求和响应都遵循相同的格式,一个HTTP包含header和body两个部分,其中body是可选的。
HTTP是一种文本协议,所以格式非常简单:
HTTP GET请求格式:

GET /path HTTP/1.1
Header1: Value1
Header2: Value2
Header3: Value3

一行一个header,换行符是\r\n
HTTP POST请求格式:

POST /path HTTP/1.1
Header1: Value1
Header2: Value2
Header3: Value3
body data goes here…

当连续遇到两个\r\n时,header部分结束时,后面的数据全是body。
HTTP 响应格式:

200 OK
Header1: Value1
Header2: Value2
Header3: Value3
body data goes here…

HTTP响应如果包含body,也是通过\r\n\r\n来划分的。body类型由content-type指定,body为文本则是网页,body为二进制数据则为图片。当存在Content-Encoding时,body数据是被压缩的,最常见的压缩方式是zip。如果看到Content-Encoding:gzip时,需要先将body数据进行解压缩,才能得到真正的数据,压缩的目的在于减少body的大小,加块网络传输。

推荐文档

如果要详细了解HTTP协议,推荐书籍HTTP: The Definitive Guide,中文译本HTTP权威指南

HTML简介

超文本标记语言:HyperText Markup Language,HTML。HTML定义了一套语法规则来对浏览器接收到的源码进行解析。
下图是一个简单的HTML

在这里插入图片描述
我们可以用编辑一个.txt文档,然后将后缀改为.html,用浏览器打开,就可以看到我们编辑的文档
在这里插入图片描述
HTML文档是由一系列的tag组成,最外层的tag是<html></html>。规范的HTML也包含<head></head><body</body>。注意,这里的head和body和HTTP的header和body不一样的。因为HTML是富文档模型,所以还有一系列tag来表示链接、图片、表格、表单等。

CSS简介

Cascading Style Sheets,层叠样式表,用来控制HTML里面的元素的展现方式,比如给标题元素添加样式,改变字号、颜色等。
在这里插入图片描述

在这里插入图片描述

JavaScript简介

JavaScript是为了让HTML具有交互性而作为脚本语言添加的,JavaScript既可以内嵌到HTML中,也可从外部链接到HTML。如果我们希望用户点击标题时把标题变成红色,就必须通过JavaScript来实现

在这里插入图片描述
单击标题后的效果:
在这里插入图片描述

小结

  • HTML定义页面内容
  • CSS控制页面元素的样式
  • JavaScript控制页面的交互逻辑
    推荐上w3school具体学习
    当我们用Python或是其他语言开发web应用,我们就要在服务器端动态创建出HTML,浏览器就会向不同的用户显示出不同的web页面。

WSGI接口简介

web应用的本质:

  1. 浏览器发送一个HTTP请求;
  2. 服务器收到请求生成HTML文档;
  3. 服务器将HTML文档作为HTTP相应的body发送给浏览器;
  4. 浏览器收到HTTP响应从HTTP的body中取出HTML文档并显示。

所以,最简单的web应用就是先把HTML用文件保存好,用一个现成的HTTP服务器软件接受用户请求,从文件中读取HTML返回。Apache、Nginx、Lighttpd等常见的静态服务器就是负责这些工作的。
如果要动态生成HTML,正确的做法是,底层代码由专门的服务器软件实现,我们用Python专注于生成HTML文档,因为我们不希望接触到TCP连接、HTTP请求和响应格式,所以需要一个统一的接口来让我们编写web业务。
WSGI:Web Server Gateway Interface,这个接口定义非常简单,只要求web开发者实现一个函数,就可以响应HTTP请求。
让我们来看一个简单的例子:

def application(environ, start_response):
    start_response('200 OK', [('Content-Type', 'text/html')])
    return [b'<h1>喵呜嗷~这是一个HTML喔</h1>']
application()

其中,application()函数是一个符合WSGI标准的HTTP处理函数,它接收两个参数:

  • environ:一个包含HTTP请求信息的dict对象;
  • start_response:一个发送HTTP响应的函数。
    在application函数中调用:start_response('200 OK', [('Content-Type', 'text/html')])就发送了HTTP响应的Header,注意Header只能发送一次,也就是这个函数只能被调用一次。start_response()接收两个参数,一个是HTTP响应码,一个是一组list表示的HTTP的Header,每个Header用一个包含两个strtuple表示。
    通常情况下都应该把Content-Type头发送给浏览器。其他很多常用的HTTP Header也应该发送。然后,函数的返回值b'<h1>Hello, web!</h1>'将作为HTTP响应的Body发送给浏览器。
    有了WSGI,我们关心的就是如何从environ这个字典对象中拿到HTTP请求信息,然后构造HTML,通过start_response()发送Header,最后返回Body。
    整个application()函数本身不涉及任何解析HTTP的部分,也就是说底层代码不需要我们编写,我们只负责在更高层次上考虑如何响应请求就可以了。
    application()函数由WSGI服务器来调用,Python内置了一个简单的WSGI服务器,模块名为wsgiref,这是一个纯Python编写的WSGI服务器的参考实现,完全符合WSGI的标准,但是不考虑运行效果,仅供开发和测试使用。

运行WSGI服务

hello.py:实现web应用程序的WSGI处理函数:

#!/usr/bin/python3
# coding=utf-8
def application(environ, start_response):
    start_response('200 OK', [('Content-Type', 'text/html')])
    return [b'<h1>喵呜嗷~这是一个HTML喔</h1>']
application()

server.py:负责启动WSGI服务器,加载application函数

#!/usr/bin/python3
# coding=utf-8
# server.py
# 从wsgiref模块导入:
from wsgiref.simple_server import make_server
# 导入我们自己编写的application函数:
from hello import application
# 创建一个服务器,IP地址为空,端口是8000,处理函数是application:
httpd = make_server('', 8000, application)
print('Serving HTTP on port 8000...')
# 开始监听HTTP请求:
httpd.serve_forever()

上面两个文件必须放在同一个目录下,然后在命令行中输入python3 server.py启动服务器:如果8000端口被占用可修改为其他端口。
在这里插入图片描述
服务器启动成功后打开浏览器输入http://localhost:8000/http://127.0.0.1:8000/查看结果:
在这里插入图片描述
命令行可以看到wsgiref打印的log信息:
在这里插入图片描述
键盘上按control+C终止服务器

小结

无论多么复杂的web应用程序,入口都只是一个WSGI处理函数,HTTP请求的所有输入信息都可以通过environ获得,HTTP响应的输出都可以通过start_response()加上函数返回值作为Body。

web框架

在学习了WSGI框架之后,我们了解到web App就是写一个WSGI的处理函数,针对每个HTTP请求进行响应。
每一个URL可以对于GET和POST请求,以及PUT、DELETE等请求,我们只考虑最常见的GET和POST请求,处理的问题就是同时处理100个不同的URL。
URL到函数的映射可以交给web框架来做,Python中有上百个开源web框架,我们直接选用比较流行的flask来使用。
用pip进行 flask安装:

pip3 install flask

编写一个app.py处理3个URL,分别是:

  • GET /:首页,返回home;
  • GET /sigin:登录页,显示登陆表单;
  • POST /signin:处理登录页表单,显示登录结果
    注意事项:同一个URL/signin分别有GET和POST两种请求,映射到两个处理函数中。flask通过Python的装饰器在内部自动地把URL与函数关联起来。
#!/usr/bin/python3
# coding=utf-8
from flask import Flask
from flask import request

app = Flask(__name__)

@app.route('/', methods=['GET', 'POST'])
def home():
    return '<h1>Home Page</h1>'

@app.route('/signin', methods=['GET'])
def signin_form():
    return '''<form action="/signin" method="post">
              <p><input name="username"></p>
              <p><input name="password" type="password"></p>
              <p><button type="submit">Sign In</button></p>
              </form>'''

@app.route('/signin', methods=['POST'])
def signin():
    # 需要从request对象读取表单内容:
    if request.form['username']=='admin' and request.form['password']=='password':
        return '<h3>Hello, admin!</h3>'
    return '<h3>Bad username or password.</h3>'

if __name__ == '__main__':
    app.run()

在命令行运行程序

python3 app.py
  • Serving Flask app “app” (lazy loading)
  • Environment: production
    WARNING: This is a development server. Do not use it in a production deployment.
    Use a production WSGI server instead.
  • Debug mode: off
  • Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
    127.0.0.1 - - [06/Aug/2019 19:28:49] “GET / HTTP/1.1” 200 -

打开浏览器地址栏,输入http://127.0.0.1:5000/显示首页:
在这里插入图片描述
再输入http://127.0.0.1:5000/ signin,显示登录表单:
在这里插入图片描述
预设的用户名和密码为adminpassword,登录成功:
在这里插入图片描述
如果输入其他用户名和密码则登录失败。

常见Python web框架

在这里插入图片描述

小结

在web框架下编写web应用时注意力就从WSGI处理函数转移到了URL和对应的处理函数上,编写web应用更加简单。在编写URL处理函数时,除了配置URL外,从HTTP请求拿到用户数据也是非常重要的,web框架提供了对应了API来实现功能。

使用模板

web框架把我们从WSGI中拯救出来,我们只需要不断编写函数带上URL就可以继续webAPP的开发了。但是webAPP不仅仅是处理逻辑,页面展示也非常重要。因为HTML的复杂,所以,展示给用户的HTML页面不仅要正确而且要整洁美观,由于在Python代码里拼接字符串不大现实,所以模块技术应运而生。
使用模板,首先准备一个嵌入了一些变量和指令的HTML文档,然后根据我们传入的数据进行替换,得到最终的发送给用户的HTML文档:

在这里插入图片描述
这就是MVC模型:Model-View-Controller,模型-视图-控制器。
Python处理URL的函数就是C:controller,控制器,controller负责业务逻辑,比如检查用户名是否存在,取出用户信息等;
包含变量{{name}}的模板就是V:view,视图,负责显示逻辑,通过简单地替换一些变量,view最终输出的就是用户看到的HTML;
model可以理解为存放和传递数据的容器,,view在替换变量的时候就是从model中取出相应的数据。
在上面的例子中,model就是一个dict{'name:':'Michael'}
Python支持关键字参数,所以很多web框架允许传入关键字参数,然后在框架内组装出一个dict作为model。
接下来我们将直接输出字符串作为HTML的例子用MVC模式改写:
app.py:

from flask import Flask, request, render_template

app = Flask(__name__)

@app.route('/', methods=['GET', 'POST'])
def home():
    return render_template('home.html')

@app.route('/signin', methods=['GET'])
def signin_form():
    return render_template('form.html')

@app.route('/signin', methods=['POST'])
def signin():
    username = request.form['username']
    password = request.form['password']
    if username=='admin' and password=='password':
        return render_template('signin-ok.html', username=username)
    return render_template('form.html', message='Bad username or password', username=username)

if __name__ == '__main__':
    app.run()

flask通过render_template()函数来实现模板的渲染。和web框架类似,Python的模板也有很多,flask默认支持的模板是jinja2:

pip3 install jinja2

接下来的三个文件需要放入同一个文件夹内,并且该文件夹和app.py在统同级文件夹中。
在这里插入图片描述
home.html:用于显示首页的模板

<html>
<head>
  <title>Home</title>
</head>
<body>
  <h1 style="font-style:italic">Home Page</h1>
</body>
</html>

form.html:显示登陆表单的模板

<html>
<head>
  <title>Please Sign In</title>
</head>
<body>
  {% if message %}
  <p style="color:red">{{ message }}</p>
  {% endif %}
  <form action="/signin" method="post">
    <legend>Please sign in:</legend>
    <p><input name="username" placeholder="Username" value="{{ username }}"></p>
    <p><input name="password" placeholder="Password" type="password"></p>
    <p><button type="submit">Sign In</button></p>
  </form>
</body>
</html>

signin-ok.html:登陆成功的模板

<html>
<head>
  <title>Welcome, {{ username }}</title>
</head>
<body>
  <p>Welcome, {{ username }}!</p>
</body>
</html>

我们在form.html中加了一点条件判断,把form.html重用为登录失败的模板。
启动app.py,在浏览器中查看模板的页面效果。
在这里插入图片描述
通过MVC模型我们在Python代码中处理Model和Controller,而View通过模板处理,这样我们就将Python代码和HTML代码最大限度地分离了。
使用模板的最大好处是模板改起来很方便,而且改完刷新浏览器即可看到效果,这对于调试HTML、CSS和JavaScript等工作而言非常重要。
在jinja2模板中,用{{name}}表示一个需要替换的变量。如果需要循环、条件判断等指令语句,则用{% ... %}表示指令
比如循环输出页码:

{% for i in page_list %}
	<a href="/page{{ i }}">{{ i }}</a>
{% endfor %}

如果page_list是一个list:[1,2,3,4,5],则上述模板将输出5个超链接。
常用模板:
在这里插入图片描述

小结

有了MVC,我们可以将Python代码和HTML代码分离,HTML放入模板可以提升代码编写效率。

总结

虽然感觉没什么收获,但还是很开心呢。

推荐文档

推荐阅读w3school-htmlw3school-css等文档。

实验文件

本实验缩写的代码

已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 精致技术 设计师:CSDN官方博客 返回首页