自定义一个简单的web框架 1纯生socket
import socket def run(): sk = socket.socket() sk.bind(('127.0.0.1', 8080)) sk.listen(5) while True: conn, addr = sk.accept() data = conn.recv(8096) # print(data) conn.send(bytes('HTTP/1.1 200 OK\r\n\r\n', encoding='utf-8')) conn.send(bytes('hello http', encoding='utf-8')) if __name__ == '__main__': run()
2根据输入不同的url,获得不一梓的相应内容 需要找到请求的uri,是/还是index/还是login
import socket def run(): sk = socket.socket() sk.bind(('127.0.0.1', 8989)) sk.listen(5) while True: conn, addr = sk.accept() data = conn.recv(8096) # print('收到的信息1', data) # 拆分请求信息,拿到uri # 拿到第一大块 header_list = str(data, encoding='utf-8').split('\r\n\r\n')[0] # print('收到的信息2', header_list[0]) # 拿到第一大块的第一行 content_list = header_list.split('\r\n')[0] # GET / HTTP/1.1 # print(content_list) uri = content_list.split(' ')[1] # / print(uri) res = None if uri == '/xxx': res = bytes('this is xxx', encoding='utf-8') elif uri == '/ooo': res = bytes('this is ooo', encoding='utf-8') elif uri == '/': res = bytes('ok', encoding='utf-8') # \r\n的斜杠不要写反了 else: res = bytes('404', encoding='utf-8') conn.send(bytes('HTTP/1.1 200 OK\r\n\r\n', encoding='utf-8')) # \r\n的斜杠不要写反了 conn.send(res) conn.close() if __name__ == '__main__': run()
3.uri 和函数的对应关系, 一下if很啰嗦 路由系统 响应一个html文件给浏览客户端,【静态网站】fn1
import socket def fn1(): # return bytes('this is xxx', encoding='utf-8') fp = open('index_3.html', 'r', encoding='utf-8') data = fp.read() return bytes(data, encoding='utf-8') # 响应一个html文件给浏览客户端 def fn2(): return bytes('this is index', encoding='utf-8') def fn3(): return bytes('this is kkk', encoding='utf-8') routes = [ ('/xxx', fn1), ('/index', fn2), ('/kkk', fn3) ] def run(): sk = socket.socket() sk.bind(('127.0.0.1', 8989)) sk.listen(5) while True: conn, addr = sk.accept() data = conn.recv(8096) # print('收到的信息1', data) # 拆分请求信息,拿到uri # 拿到第一大块 header_list = str(data, encoding='utf-8').split('\r\n\r\n')[0] # print('收到的信息2', header_list[0]) # 拿到第一大块的第一行 content_list = header_list.split('\r\n')[0] # GET / HTTP/1.1 # print(content_list) uri = content_list.split(' ')[1] # / # print(uri) func_name = None for key in routes: if uri in key: func_name = key[1] break if func_name: res = func_name() else: res = bytes('404 not found', encoding='utf-7') conn.send(bytes('HTTP/1.1 200 OK\r\n\r\n', encoding='utf-8')) # \r\n的斜杠不要写反了 conn.send(res) conn.close() if __name__ == '__main__': run()
4.响应一个动态文件给浏览客户端: fn2
import socket import time def fn1(): # return bytes('this is xxx', encoding='utf-8') fp = open('index_3.html', 'r', encoding='utf-8') data = fp.read() return bytes(data, encoding='utf-8') # 响应一个html文件给浏览客户端 def fn2(): # return bytes('this is index', encoding='utf-8') ctime = str(time.time()) fp = open('article_4.html', 'r', encoding='utf-8') data = fp.read() res = data.replace('@@content@@', ctime) return bytes(res, encoding='utf-8') def fn3(): return bytes('this is kkk', encoding='utf-8') routes = [ ('/xxx', fn1), ('/index', fn2), ('/kkk', fn3) ] def run(): sk = socket.socket() sk.bind(('127.0.0.1', 8989)) sk.listen(5) while True: conn, addr = sk.accept() data = conn.recv(8096) # print('收到的信息1', data) # 拆分请求信息,拿到uri # 拿到第一大块 header_list = str(data, encoding='utf-8').split('\r\n\r\n')[0] # print('收到的信息2', header_list[0]) # 拿到第一大块的第一行 content_list = header_list.split('\r\n')[0] # GET / HTTP/1.1 # print(content_list) uri = content_list.split(' ')[1] # / # print(uri) func_name = None for key in routes: if uri in key: func_name = key[1] break if func_name: res = func_name() else: res = bytes('404 not found', encoding='utf-7') conn.send(bytes('HTTP/1.1 200 OK\r\n\r\n', encoding='utf-8')) # \r\n的斜杠不要写反了 conn.send(res) conn.close() if __name__ == '__main__': run()
5.响应数据库内容 模板渲染 需要将html代码和mysql结果融合
def fn3(): # 通过pymysql拿到数据库中数据 # return bytes('this is kkk', encoding='utf-8') import pymysql conn = pymysql.connect(host='127.0.0.1', user='root', password='999', db='db4', charset='utf8') cursor = conn.cursor(cursor=pymysql.cursors.DictCursor) sql = 'select id, name, extra, type_id from user' cursor.execute(sql) res = cursor.fetchall() print(res) # [{'id': 1, 'name': 'egon', 'extra': '', 'type_id': 1}, # {'id': 2, 'name': 'jerry', 'extra': '', 'type_id': 2},] # 将html代码和mysql结果融合 # 将该数据写入表格,替换 # 拼接 str_list = [] for user in res: res_str = '%s%s%s%s' % (user['id'], user['name'], user['extra'], user['type_id'],) str_list.append(res_str) s = ''.join(str_list) # 替换 fp = open('content_5.html', 'r', encoding='utf-8') data = fp.read() res = data.replace('@@content@@', s) return bytes(res, encoding='utf-8')
6.server_jinjia表单
def fn4(): import pymysql conn = pymysql.connect(host='127.0.0.1', user='root', password='999', db='db4', charset='utf8') cursor = conn.cursor(cursor=pymysql.cursors.DictCursor) sql = 'select id, name, extra, type_id from user' cursor.execute(sql) users = cursor.fetchall() fp = open('contentjinja2_5.html', 'r', encoding='utf-8') data = fp.read() from jinja2 import Template template = Template(data) data = template.render(users=users)
Django的基础
web请求流程
所有的web应用本质上就是一个socket服务端,用户的浏览器就是一个socket客户端,即b/s架构,基于http协议,工作在应用层.
http协议
Hyper Text Transfer Protocol,超文本传输协议,是一种建立在TCP上的无状态,一次性连接.它限制每次连接只处理一个请求,当服务器返回本次请求的应答后便立即关闭连接,下次请求再重新建立连接。
1.客户端和服务器建立连接,
2.客户端发送一个HTTP请求,说明想要访问的资源和请求的动作,
3.服务端收到请求之后,服务端开始处理请求,并根据请求做出相应的动作访问服务器资源,最后通过发送HTTP响应把结果返回给客户端
4.客户端与服务器关闭连接
其中一个请求的开始到一个响应的结束称为事务,当一个事物结束后还会在服务端添加一条日志条目。
DNS工作流程
DNS协议:域名系统,域名和ip地址相互映射的一个分布式数据库(基于udp协议).
工作流程:
1.打开浏览器,输入网址,客户端发送请求.
2.收到请求后,先在本地DNS服务器缓存中查找有没有这条记录.如果有该纪录项,则本地的域名服务器就直接把查询的结果返回。
3.没有,就去根域名服务器中找域名中的顶级域名(.com, .net, .cn, .org),将顶级域名中的服务器地址返回给本地DNS服务器.
4.本地服务器拿到顶级域名服务器地址后,,给顶级域名服务器发送请求,顶级域名服务器查询域名对应的ip地址.
5.顶级域名服务器将请求中的二级域名信息返回给本地服务器
6.本地服务器拿到信息后,给二级域名发送请求.二级域名服务器查询域名对应的ip地址.
7.二级域名服务器将查找到的返回给本地DNS服务器
8.本地服务器将拿到的结果缓存在自己的服务器中,以便下次查找,同时将结果返回给客户端.
本地DNS的查找:
C: --> Windoes -->System32 --> drivers --> etc --> hosts
当在浏览器输入url,按下回车时,到返回页面,描述过程.
收到请求后,先在dns系统中查找域名所对应的ip地址,然后dns系统将查找到的ip地址返回给浏览器,浏览器拿到ip地址后,给ip相对应的服务器发送请求.
自定义web框架
import socket server = socket.socket() server.bind(('127.0.0.1',8080)) server.listen(5) while True: connect,addr = server.accept() buf = connect.recv(1024) connect.send(bytes('HTTP1.1 200 OK\r\n\r\n', encoding='utf-8')) connect.send(bytes('hello world', encoding=('utf-8'))) connect.close()
Http协议:
得到的数据
请求头: GET / HTTP/1.1 Host: 127.0.0.1:8080 (主机名) Connection: keep-alive (保持链接) Cache-Control: max-age=0 (缓存不失效) Upgrade-Insecure-Requests: 1 User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3 Accept-Encoding: gzip, deflate, br Accept-Language: zh-CN,zh;q=0.9 Token: bdsjalbdjsalbdjsa 请求体: bdsabdjsabjddas 响应头: HTTP/1.1 200 OK 响应体: 自己看到的内容 http: 默认端口是80 Https: 默认的端口是443 状态码
1XX:通知 2XX: 成功 200 (ok) 3XX 重定向 302(Found) 304(Not Modified) 4XX:客户端错误 403(forbidden 禁止访问) 404(not found) 5XX 服务端错误 500 (服务端代码错误) 502 (网关错误 bad gateway)