我们可以这理解:所有的Web应用本质上就是一个socket服务端,而用户的浏览器就是一个socket客户端。
""" 不完善的web服务端示例 """ import socket # 生成socket示例对象 sk = socket.socket() # 绑定IP端口 sk.bind(("127.0.0.1",8080)) # 监听 sk.listen() # 写一个死循环,一直等待客户端来连接 while True: # 获取与客户端的连接 conn,addr = sk.accept() # 接收客户端发来的消息 data = conn.recv(8096) print(data) # 给客户端回复消息 # conn.send(b‘http/1.1 200 OK\r\ncontent-type:text/html;charset=utf-8\r\n\r\n‘) # 想让浏览器在页面上显示出来的内容都是响应正文 conn.send(b‘<h1>s10</h1>‘) conn.close() sk.close()
HTTP协议就是对浏览器的发送消息和服务端的响应信息作出一个统一的规则
import socket sk = socket.socket() sk.bind(("127.0.0.1", 80)) sk.listen() while True: conn, addr = sk.accept() data = conn.recv(8096) print(data) # 将浏览器发来的消息打印出来 conn.send(b"OK") conn.close()
b‘GET / HTTP/1.1\r\nHost: 127.0.0.1:8080\r\nConnection: keep-alive\r\nUpgrade-Insecure-Requests: 1\r\nUser-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.186 Safari/537.36\r\nAccept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8\r\nDNT: 1\r\nAccept-Encoding: gzip, deflate, br\r\nAccept-Language: zh-CN,zh;q=0.9\r\nCookie: csrftoken=RKBXh1d3M97iz03Rpbojx1bR6mhHudhyX5PszUxxG3bOEwh1lxFpGOgWN93ZH3zv\r\n\r\n‘
经过上面的补充学习,我们知道了要想让我们自己写的web server端正经起来,必须要让我们的Web server在给客户端回复消息的时候按照HTTP协议的规则加上响应状态行,这样我们就实现了一个正经的Web框架了。
""" 完善的web服务端示例 """ import socket # 生成socket示例对象 sk = socket.socket() # 绑定IP端口 sk.bind(("127.0.0.1",8081)) # 监听 sk.listen() # 写一个死循环,一直等待客户端来连接 while True: # 获取与客户端的连接 conn,addr = sk.accept() # 接收客户端发来的消息 data = conn.recv(8096) print(data) # 给客户端回复消息 conn.send(b‘http/1.1 200 OK\r\ncontent-type:text/html;charset=utf-8\r\n\r\n‘) # 想让浏览器在页面上显示出来的内容都是响应正文 conn.send(b‘<h1>s10</h1>‘) # conn.close() # sk.close()
""" 完善的web服务端示例 根据不同的路径返回不同的内容 """ import socket # 生成socket示例对象 sk = socket.socket() # 绑定IP端口 sk.bind(("127.0.0.1",8082)) # 监听 sk.listen() # 写一个死循环,一直等待客户端来连接 while True: # 获取与客户端的连接 conn,addr = sk.accept() # 接收客户端发来的消息 data = conn.recv(8096) data_str = str(data,encoding="utf-8") print(data_str) # 用\r\n去切割上面的字符串 l1 = data_str.split("\r\n") print(l1[0]) # 按照空格去切割上面的字符串 l2 = l1[0].split() url = l2[1] print(url) # 给客户端回复消息 conn.send(b‘http/1.1 200 OK\r\ncontent-type:text/html;charset=utf-8\r\n\r\n‘) # 想让浏览器在页面上显示出来的内容都是响应正文 if url == "/yimi/": response = b‘<h1>hello yimi</h1>‘ elif url == "/xiaohei/": response = b‘<h1>hello xiaohei</h1>‘ else: response = b‘<h1>404!not fund!</h1>‘ conn.send(response) # conn.close() # sk.close()
""" 完善的web服务端示例 函数版根据不同的路径返回不同的内容 """ import socket # 生成socket示例对象 sk = socket.socket() # 绑定IP端口 sk.bind(("127.0.0.1",8083)) # 监听 sk.listen() # 定义一个处理/yimi/的函数 def yimi(url): ret = ‘hello {}‘.format(url) return bytes(ret,encoding="utf-8") # 定义一个处理/xiaohei/的函数 def xiaohei(url): ret = ‘hello {}‘.format(url) return bytes(ret,encoding="utf-8") # 写一个死循环,一直等待客户端来连接 while True: # 获取与客户端的连接 conn,addr = sk.accept() # 接收客户端发来的消息 data = conn.recv(8096) data_str = str(data,encoding="utf-8") print(data_str) # 用\r\n去切割上面的字符串 l1 = data_str.split("\r\n") print(l1[0]) # 按照空格去切割上面的字符串 l2 = l1[0].split() url = l2[1] print(url) # 给客户端回复消息 conn.send(b‘http/1.1 200 OK\r\ncontent-type:text/html;charset=utf-8\r\n\r\n‘) # 想让浏览器在页面上显示出来的内容都是响应正文 # 根据不同的url返回不同的内容 if url == "/yimi/": response = yimi(url) elif url == "/xiaohei/": response = xiaohei(url) else: response = b‘<h1>404!not fund!</h1>‘ conn.send(response) # conn.close() # sk.close()
""" 完善的web服务端示例 函数版根据不同的路径返回不同的内容 进阶函数版 不写if判断了,用url名字去找对应的函数名 """ import socket # 生成socket示例对象 sk = socket.socket() # 绑定IP端口 sk.bind(("127.0.0.1",8084)) # 监听 sk.listen() # 定义一个处理/yimi/的函数 def yimi(url): ret = ‘hello {}‘.format(url) return bytes(ret,encoding="utf-8") # 定义一个处理/xiaohei/的函数 def xiaohei(url): ret = ‘hello {}‘.format(url) return bytes(ret,encoding="utf-8") # 定义一个专门来处理404的函数 def f404(url): ret = "你访问的这个{}找不到".format(url) return bytes(ret,encoding="utf-8") url_func = [ ("/yimi/",yimi), ("/xiaohei/",xiaohei), ] # 写一个死循环,一直等待客户端来连接 while True: # 获取与客户端的连接 conn,addr = sk.accept() # 接收客户端发来的消息 data = conn.recv(8096) data_str = str(data,encoding="utf-8") print(data_str) # 用\r\n去切割上面的字符串 l1 = data_str.split("\r\n") print(l1[0]) # 按照空格去切割上面的字符串 l2 = l1[0].split() url = l2[1] print(url) # 给客户端回复消息 conn.send(b‘http/1.1 200 OK\r\ncontent-type:text/html;charset=utf-8\r\n\r\n‘) # 想让浏览器在页面上显示出来的内容都是响应正文 # 根据不同的url返回不同的内容 # 去url_func里面找对应关系 for i in url_func: if i[0] == url: func = i[1] break # 找不到对应关系就默认执行404函数 else: func = f404 # 拿到函数的执行结果 response = func(url) # 将函数返回的结果发给浏览器 conn.send(response) # conn.close() # sk.close()
""" 完善的web服务端示例 函数版根据不同的路径返回不同的内容 进阶函数版 不写if判断了,用url名字去找对应的函数名 返回html页面 """ import socket # 生成socket示例对象 sk = socket.socket() # 绑定IP端口 sk.bind(("127.0.0.1",8085)) # 监听 sk.listen() # 定义一个处理/yimi/的函数 def yimi(url): with open("yimi.html","rb") as f: ret = f.read() return ret # 定义一个处理/xiaohei/的函数 def xiaohei(url): with open("xiaohei.html","rb") as f: ret = f.read() return ret # 定义一个专门来处理404的函数 def f404(url): ret = "你访问的这个{}找不到".format(url) return bytes(ret,encoding="utf-8") url_func = [ ("/yimi/",yimi), ("/xiaohei/",xiaohei), ] # 写一个死循环,一直等待客户端来连接 while True: # 获取与客户端的连接 conn,addr = sk.accept() # 接收客户端发来的消息 data = conn.recv(8096) data_str = str(data,encoding="utf-8") print(data_str) # 用\r\n去切割上面的字符串 l1 = data_str.split("\r\n") print(l1[0]) # 按照空格去切割上面的字符串 l2 = l1[0].split() url = l2[1] print(url) # 给客户端回复消息 conn.send(b‘http/1.1 200 OK\r\ncontent-type:text/html;charset=utf-8\r\n\r\n‘) # 想让浏览器在页面上显示出来的内容都是响应正文 # 根据不同的url返回不同的内容 # 去url_func里面找对应关系 for i in url_func: if i[0] == url: func = i[1] break # 找不到对应关系就默认执行404函数 else: func = f404 # 拿到函数的执行结果 response = func(url) # 将函数返回的结果发给浏览器 conn.send(response) # conn.close() # sk.close()
""" 根据URL中不同的路径返回不同的内容--函数进阶版 返回HTML页面 让网页动态起来 """ import socket import time sk = socket.socket() sk.bind(("127.0.0.1", 8080)) # 绑定IP和端口 sk.listen() # 监听 # 将返回不同的内容部分封装成函数 def index(url): with open("index.html", "r", encoding="utf8") as f: s = f.read() now = str(time.time()) s = s.replace("@@oo@@", now) # 在网页中定义好特殊符号,用动态的数据去替换提前定义好的特殊符号 return bytes(s, encoding="utf8") def home(url): with open("home.html", "r", encoding="utf8") as f: s = f.read() return bytes(s, encoding="utf8") # 定义一个url和实际要执行的函数的对应关系 list1 = [ ("/index/", index), ("/home/", home), ] while 1: # 等待连接 conn, add = sk.accept() data = conn.recv(8096) # 接收客户端发来的消息 # 从data中取到路径 data = str(data, encoding="utf8") # 把收到的字节类型的数据转换成字符串 # 按\r\n分割 data1 = data.split("\r\n")[0] url = data1.split()[1] # url是我们从浏览器发过来的消息中分离出的访问路径 conn.send(b‘HTTP/1.1 200 OK\r\n\r\n‘) # 因为要遵循HTTP协议,所以回复的消息也要加状态行 # 根据不同的路径返回不同内容 func = None # 定义一个保存将要执行的函数名的变量 for i in list1: if i[0] == url: func = i[1] break if func: response = func(url) else: response = b"404 not found!" # 返回具体的响应消息 conn.send(response) conn.close()
WSGI(Web Server Gateway Interface)就是一种规范,它定义了使用Python编写的web应用程序与web服务器程序之间的接口格式,实现web应用程序与web服务器程序间的解耦。
常用的WSGI服务器有uwsgi、Gunicorn。而Python标准库提供的独立WSGI服务器叫wsgiref,Django开发环境用的就是这个模块来做服务器。
""" 根据URL中不同的路径返回不同的内容--函数进阶版 返回HTML页面 让网页动态起来 wsgiref模块版 """ import time from wsgiref.simple_server import make_server # 将返回不同的内容部分封装成函数 def index(url): with open("index.html", "r", encoding="utf8") as f: s = f.read() now = str(time.time()) s = s.replace("@@oo@@", now) return bytes(s, encoding="utf8") def home(url): with open("home.html", "r", encoding="utf8") as f: s = f.read() return bytes(s, encoding="utf8") # 定义一个url和实际要执行的函数的对应关系 list1 = [ ("/index/", index), ("/home/", home), ] def run_server(environ, start_response): start_response(‘200 OK‘, [(‘Content-Type‘, ‘text/html;charset=utf8‘), ]) # 设置HTTP响应的状态码和头信息 url = environ[‘PATH_INFO‘] # 取到用户输入的url func = None for i in list1: if i[0] == url: func = i[1] break if func: response = func(url) else: response = b"404 not found!" return [response, ] if __name__ == ‘__main__‘: httpd = make_server(‘127.0.0.1‘, 8090, run_server) print("我在8090等你哦...") httpd.serve_forever()
上面的代码实现了一个简单的动态,我完全可以从数据库中查询数据,然后去替换我html中的对应内容,然后再发送给浏览器完成渲染。 这个过程就相当于HTML模板渲染数据。 本质上就是HTML内容中利用一些特殊的符号来替换要展示的数据。 我这里用的特殊符号是我定义的,其实模板渲染有个现成的工具:
pip install jinja2
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <meta http-equiv="x-ua-compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>Title</title> </head> <body> <h1>姓名:{{name}}</h1> <h1>爱好:</h1> <ul> {% for hobby in hobby_list %} <li>{{hobby}}</li> {% endfor %} </ul> </body> </html>
from wsgiref.simple_server import make_server from jinja2 import Template def index(): with open("index2.html", "r") as f: data = f.read() template = Template(data) # 生成模板文件 ret = template.render({"name": "Alex", "hobby_list": ["烫头", "泡吧"]}) # 把数据填充到模板里面 return [bytes(ret, encoding="utf8"), ] def home(): with open("home.html", "rb") as f: data = f.read() return [data, ] # 定义一个url和函数的对应关系 URL_LIST = [ ("/index/", index), ("/home/", home), ] def run_server(environ, start_response): start_response(‘200 OK‘, [(‘Content-Type‘, ‘text/html;charset=utf8‘), ]) # 设置HTTP响应的状态码和头信息 url = environ[‘PATH_INFO‘] # 取到用户输入的url func = None # 将要执行的函数 for i in URL_LIST: if i[0] == url: func = i[1] # 去之前定义好的url列表里找url应该执行的函数 break if func: # 如果能找到要执行的函数 return func() # 返回函数的执行结果 else: return [bytes("404没有该页面", encoding="utf8"), ] if __name__ == ‘__main__‘: httpd = make_server(‘‘, 8000, run_server) print("Serving HTTP on port 8000...") httpd.serve_forever()
conn = pymysql.connect(host="127.0.0.1", port=3306, user="root", passwd="xxx", db="xxx", charset="utf8") cursor = conn.cursor(cursor=pymysql.cursors.DictCursor) cursor.execute("select name, age, department_id from userinfo") user_list = cursor.fetchall() cursor.close() conn.close()
CREATE TABLE user( id int auto_increment PRIMARY KEY, name CHAR(10) NOT NULL, hobby CHAR(20) NOT NULL )engine=innodb DEFAULT charset=UTF8;
模板的原理就是字符串替换,我们只要在HTML页面中遵循jinja2的语法规则写上,其内部就会按照指定的语法进行相应的替换,从而达到动态的返回内容。
pip3 install django==1.11.9
django-admin startproject mysite
python manage.py runserver 127.0.0.1:8080
TEMPLATES = [ { ‘BACKEND‘: ‘django.template.backends.django.DjangoTemplates‘, ‘DIRS‘: [os.path.join(BASE_DIR, "template")], # template文件夹位置 ‘APP_DIRS‘: True, ‘OPTIONS‘: { ‘context_processors‘: [ ‘django.template.context_processors.debug‘, ‘django.template.context_processors.request‘, ‘django.contrib.auth.context_processors.auth‘, ‘django.contrib.messages.context_processors.messages‘, ], }, }, ]
STATIC_URL = ‘/static/‘ # HTML中使用的静态文件夹前缀 STATICFILES_DIRS = [ os.path.join(BASE_DIR, "static"), # 静态文件存放位置 ]
内部传入一个字符串参数,返回给浏览器。
例如:
def index(request): # 业务逻辑代码 return HttpResponse("OK")
除request参数外还接受一个待渲染的模板文件和一个保存具体数据的字典参数。
将数据填充进模板文件,最后把结果返回给浏览器。(类似于我们上面用到的jinja2)
例如:
def index(request): # 业务逻辑代码 return render(request, "index.html", {"name": "alex", "hobby": ["烫头", "泡吧"]})
接受一个URL参数,表示跳转到指定的URL。
例如:
def index(request): # 业务逻辑代码 return redirect("/home/")
原文:https://www.cnblogs.com/Big-Dinosaur/p/9998070.html