一:Django框架应用
1:web应用:运行在浏览器上的应用
2:c/s,b/s架构
client/server:客户端服务器架构,c++
browser/server:浏览器服务器架构,java,Python
底层均是基于socket
3:Python web框架
a:socket b:页面路由 c:模板渲染
Django a用到wsgiref b自己写的 c 自己写的 功能全面
Flask a用的第三方 b自己写的 c自己写的 小而轻
Tornado a自己写的 b自己写的 c自己写的 支持高并发
二:原生socket服务
目录结构:
part1
-- index.html
-- server.py
基础socket服务:

import socket
# 利用socket建立服务器对象
server = socket.socket()
# 设置ip和端口
server.bind(('127.0.0.1', 8001))
# 设置监听
server.listen(5)
print('服务器设置成功')
print('浏览器访问:http://127.0.0.1:8001')
while True:
# 阻塞等待客户端数据
client, address = server.accept()
# 接收数据
data = client.recv(1024)
print('接收到数据: ', data)
# 返回数据
client.send(b'Normal Socket Web')
# 关闭连接(必须关闭每一次连接)
client.close()
# 浏览器错误:发送的响应无效,原因:响应不满足http协议
'''
# 请求发来的数据
b'GET / HTTP/1.1\r\n
Host: 127.0.0.1:8001\r\n
Connection: keep-alive\r\n
Upgrade-Insecure-Requests: 1\r\n
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36\r\n
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8\r\n
Accept-Encoding: gzip, deflate, br\r\n
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8\r\n
Cookie: csrftoken=szfYLDVuqvRhlveNpNE2rp1GYOcI5x7mRNfvkRWTMRNRwWxXMZWOhL1MqknYJ7jg; sessionid=3pphvmw2icub0bea7nn02u6wev17k4uw\r\n
\r\n'
'''

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>测试请求</title>
</head>
<body>
<div>GET</div>
<form action="http://127.0.0.1:8801" method="GET">
<input type="text" name="get_usr">
<input type="submit" value="get提交">
</form>
<div>POST</div>
<form action="http://127.0.0.1:8801" method="POST">
<input type="text" name="post_usr">
<input type="submit" value="post提交">
</form>
</body>
</html>
三:HTTP协议
1:什么是HTTP协议
HTTP(HyperText Transport Protocol)是超文本传输协议
基于TCP/IP洗衣的基础上的应用协议,底层实现仍为socket
基于请求--响应模式:通信一定是从客户端开始,服务器接收到客户端一定会做出对应响应
无状态:协议不对任何一次通信状态和任何数据做保存
无连接:一次连接只完成一次请求--响应,请求--响应完毕后会立即断开连接

2.HTTP工作原理(事务)
一次HTTP操作称之为一个事务,工作过程可分为四步:
1:客户端与服务端建立连接
2:客户端发生一个HTTP协议指定格式的请求
3:服务器端接收请求后,响应一个HTTP协议指定格式的响应
4:客户端将服务器的响应显示展现给用户
3.请求报文
请求行:GET|POST(请求方式) / (请求路径) HTTP / 1.1(HTTP协议版本)
请求头:了解
请求体: GET请求体放在请求路径后进行拼接 POST会在请求行与请求头结束后,以数据包方式单独发送
POST / HTTP/1.1\r\n Host: 127.0.0.1:8001\r\n Connection: keep-alive\r\n Upgrade-Insecure-Requests: 1\r\n User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36\r\n Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8\r\n Accept-Encoding: gzip, deflate, br\r\n Accept-Language: zh-CN,zh;q=0.9,en;q=0.8\r\n \r\n usr=abc&pwd=123
4.响应报文
响应行(一定有):HTTP/1.1(http协议版本) 200(状态码) OK(状态结束)
响应头:(了解)
响应体:具体的数据
HTTP/1.1 200 OK\r\n Content-type:text/html\r\n \r\n Login Success
5.状态码
1打头:消息通知
2打头:请求成功
3打头:重定向
4打头:客户端错误(404)
5打头:服务器端错误
四:练习代码:
part2:目录


import socket
PORT = 8802
def index():
return b'home page'
pass
def login():
with open('login.html', 'rb') as f:
login_data = f.read()
return login_data
def ico():
with open('keji.jpg', 'rb') as f:
ico_data = f.read()
return ico_data
method_dic = {
'/': index,
'/index': index,
'/login': login,
'/favicon.ico': ico,
}
server = socket.socket()
server.bind(('127.0.0.1', PORT))
server.listen(5)
print("服务端启动:http://127.0.0.1:%s" % PORT)
# 1.浏览器采用http协议方式发生请求
while True:
browser, _ = server.accept()
req_data = browser.recv(1024).decode('utf-8')
# print(req_data)
browser.send(b'HTTP/1.1 200 OK\r\n')
browser.send(b'Content-type:text/html\r\n')
browser.send(b'\r\n')
# 请求路径有多种多样 => 具体请求路径应该交给具体的功能处理完成对应的响应
path = req_data.split('\r\n')[0].split(" ")[1]
print(path)
# print()
resp_data = b'<h1 style="text-align: center">404</h1>'
if path in method_dic:
resp_data = method_dic[path]()
browser.send(resp_data)
browser.close()

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>登录页面</title>
</head>
<body>
<form action="">
<input type="text" name="usr">
<input type="password" name="pwd">
<input type="submit" value="登录">
</form>
</body>
</html>
可以根据请求HTTP协议数据,解析出请求路径,根据具体路径完成业务逻辑方法,完成对应的响应。
1:业务逻辑会不断增加,所以业务逻辑要分层单独处理
2:路径与业务处理方法对应关系也会越来越多,越来越复杂,也可以分离单独处理
3:自定义服务器功能不健全,稳定性差,可以选择第三方
改善part2写的part3:
目录:


<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>测试请求</title>
</head>
<body>
<div>GET</div>
<form action="http://127.0.0.1:8803" method="GET">
<input type="text" name="get_usr">
<input type="submit" value="get提交">
</form>
<div>POST</div>
<form action="http://127.0.0.1:8803" method="POST">
<input type="text" name="post_usr">
<input type="submit" value="post提交">
</form>
</body>
</html>

# 使用遵循了WSGI协议的第三方server
from wsgiref import simple_server
from day62.教案.part3.urls import urls
PORT = 8803
def send_request(url):
resp_data = b'404'
if url in urls:
resp_data = urls[url]()
return resp_data
def app(environ, response):
# 请求的数据被解析在environ字典中
print(environ) # 请求方式REQUEST_METHOD 请求路径PATH_INFO
path = environ['PATH_INFO']
print(path)
# 数据的获取
# GET 在environ的QUERY_STRING字段中,eg:usr=abc&pwd=123
# POST 数据长度CONTENT_LENGTH 数据存放的io流 wsgi.input eg: usr=abc&pwd=123
# length = int(environ['CONTENT_LENGTH'])
# res = environ['wsgi.input'].read(length)
# print(res)
# 将数据转换成字典
resp_data = send_request(path)
# 用response来规定http响应结果
# print(response)
response("200 OK", [('Content-type', 'text/html')])
# 返回的是装有二进制数据的数组
return [resp_data]
if __name__ == '__main__':
server = simple_server.make_server('127.0.0.1', PORT, app)
print("服务启动:http://127.0.0.1:%s" % PORT)
# 保持server运行
server.serve_forever()
# 利用第三方wsgiref服务器完成请求-响应

from part3.views import *
urls = {
'/': index,
'/index': index,
'/favicon.ico': ico,
'/login': login,
}

# 结果要返回二进制数据
def ico():
with open('keji.jpg', 'rb') as f:
ico_data = f.read()
return ico_data
def index():
return b'home page'
pass
def login():
with open('login.html', 'rb') as f:
login_data = f.read()
return login_data
五:jinjia2
Jinjia2是基于Python下一个被广泛应用的模板引擎,来源于Django的模板引擎,并扩展了其语法和一系列强大的功能,最显著的是增加了沙箱执行功能和可选的自动转义功能,者对于大多数的安全性来说是非常重要的。(基于Unicode并能在Python2.4之后的版本运行,包括Python3)
有Jinjia改的part4:
目录:


<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>login result</title>
</head>
<body>
<!--my login page => %%res%%-->
my login page => {{ result }}
<hr>
{{my_dic}}
<hr>
{% for k in my_dic %}
<div>{{k}} : {{my_dic[k]}}</div>
{% endfor %}
</body>
</html>

from wsgiref import simple_server
from part4.urls import urls
PORT = 8804
# 浏览器通过:http://127.0.0.1:8804/login?usr=abc&pwd=123 来模拟get方式登录
def app(environ, response):
print(environ)
response("200 OK", [('Content-type', 'text/html')])
url = environ['PATH_INFO']
res_dic = {}
if environ.get('REQUEST_METHOD', None) == "GET" and url == "/login":
res_str = environ['QUERY_STRING'] # usr=abc&pwd=123
if res_str: # 如果没有请求提交的数据,就不需要解析数据
res_list = res_str.split('&') # ['usr=abc', 'pwd=123']
for k_v_m in res_list: # k_v_m: 'usr=abc' | 'pwd=123'
k_v_l = k_v_m.split('=') # ['usr', 'abc'] | ['pwd', '123']
res_dic[k_v_l[0]] = k_v_l[1]
resp_data = b'404'
if url in urls:
resp_data = urls[url](res_dic)
return [resp_data]
if __name__ == '__main__':
server = simple_server.make_server('127.0.0.1', PORT, app)
print("服务启动:http://127.0.0.1:%s" % PORT)
# 保持server运行
server.serve_forever()

from day62.教案.part4.views import *
urls = {
'/': index,
'/index': index,
'/favicon.ico': ico,
'/login': login,
}

# 结果要返回二进制数据
import pymysql
from jinja2 import Template
def ico(dic=None):
with open('keji.jpg', 'rb') as f:
ico_data = f.read()
return ico_data
def index(dic=None):
return b'home page'
pass
def login(dic=None):
print(dic)
usr = dic['usr']
pwd = dic['pwd']
# 和数据库进行交互
conn = pymysql.connect(
host='127.0.0.1',
db='dg1',
user='root',
passwd='root'
)
cursor = conn.cursor(pymysql.cursors.DictCursor)
row = cursor.execute('select * from user where usr=%s and pwd = %s', [usr, pwd])
# 根据结果渲染动态页面 => 利用第三方jinja2
# with open('login.html', 'rt') as f:
# msg = f.read()
#
# if row:
# res = 'login success'
# else:
# res = 'login failed'
#
# msg = msg.replace("%%res%%", res)
# 模板渲染框架定义了很多模板语法,采用这些语法可以复用html代码
with open('login.html', 'rt') as f:
msg = f.read()
tem = Template(msg)
if row:
res = 'login success'
else:
res = 'login failed'
msg = tem.render(result=res, my_dic=dic)
return msg.encode('utf-8')
来源:https://www.cnblogs.com/liuxiaolu/p/10431725.html
