一、HTTP 协议 1、HTTP 协议
HTTP 协议全称:HyperText Transfer Protocol,即超文本传输协议
HTTP 协议由蒂姆·伯纳斯-李在1991年设计出来,最初目的是传输网页数据,后来允许传输任意类型的数据
HTTP 协议规定了浏览器和 Web 服务器通信数据的格式,即浏览器和Web服务器通信需要使用 HTTP协议
2、浏览器访问web服务器的通信过程
传输 HTTP 协议格式的数据是基于 TCP 传输协议的,发送数据之前需要先建立连接
二、URL 1、 URL的概念
URL全称:Uniform Resoure Locator,即统一资源定位符,也叫网络资源地址(网址)
2、URL的组成
三、查看 HTTP 通信过程 1、打开开发者工具(以谷歌为例)
Windows和Linux平台:快捷键F12
mac OS:快捷键alt+command+i
多平台通用:右击选择检查
2、开发者工具的标签选项
Elements(元素):用于查看或修改HTML标签
Console(控制台):可以执行js代码
Sources(源代码):查看静态资源文件,断点调试JS代码
Network(网络):查看每一次请求和响应的通信过程
3、开发者工具中Network的Headers选项
General:主要信息
Response Headers:响应头
Request Headers:请求头
Response:响应体
四、HTTP 请求 1、HTTP常见请求报文
GET请求:获取web服务器数据
POST请求:向web服务器提交数据并获取web服务器数据
2、GET 请求
1 2 3 4 5 6 7 8 9 10 11 12 ---- 请求行 ---- GET / HTTP/1.1 # GET请求方式 请求资源路径 HTTP协议版本 ---- 请求头 ----- Host: www.itcast.cn # 服务器的主机地址和端口号,默认是80 Connection: keep-alive # 和服务端保持长连接 Upgrade-Insecure-Requests: 1 # 让浏览器升级不安全请求,使用https请求 User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36 # 用户代理 Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8 # 可接受的数据类型 Accept-Encoding: gzip, deflate # 可接受的压缩格式 Accept-Language: zh-CN,zh;q=0.9 #可接受的语言 Cookie: pgv_pvi=1246921728; # 登录用户的身份标识 ---- 空行 ----
1 2 3 4 5 6 7 8 9 10 GET / HTTP/1.1\r\n Host: www.itcast.cn\r\n Connection: keep-alive\r\n Upgrade-Insecure-Requests: 1\r\n User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 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\r\n Accept-Language: zh-CN,zh;q=0.9\r\n Cookie: pgv_pvi=1246921728; \r\n \r\n
3、POST 请求
1 2 3 4 5 6 7 8 9 10 ---- 请求行 ---- POST /xmweb?host=mail.itcast.cn&_t=1542884567319 HTTP/1.1 # POST请求方式 请求资源路径 HTTP协议版本 ---- 请求头 ---- Host: mail.itcast.cn # 服务器的主机地址和端口号,默认是80 Connection: keep-alive # 和服务端保持长连接 Content-Type: application/x-www-form-urlencoded # 告诉服务端请求的数据类型 User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36 # 客户端的名称 ---- 空行 ---- ---- 请求体 ---- username=hello&pass=hello # 请求参数
1 2 3 4 5 6 7 POST /xmweb?host=mail.itcast.cn&_t=1542884567319 HTTP/1.1\r\n Host: mail.itcast.cn\r\n Connection: keep-alive\r\n Content-Type: application/x-www-form-urlencoded\r\n User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36\r\n \r\n(请求头信息后面还有一个单独的’\r\n’不能省略) username=hello&pass=hello
五、HTTP 响应 1、响应报文
1 2 3 4 5 6 7 8 9 10 11 12 13 --- 响应行/状态行 --- HTTP/1.1 200 OK # HTTP协议版本 状态码 状态描述 --- 响应头 --- Server: Tengine # 服务器名称 Content-Type: text/html; charset=UTF-8 # 内容类型 Transfer-Encoding:chunked # 发送给客户端内容不确定内容长度,发送结束的标记是0\r\n, Content-Length:表示服务端确定发送给客户端的内容大小,与Transfer-Encoding二者只能用其一 Connection: keep-alive # 和客户端保持长连接 Date: Fri, 23 Nov 2018 02:01:05 GMT # 服务端的响应时间 --- 空行 --- --- 响应体 --- <!DOCTYPE html><html lang=“en”> …</html> # 响应给客户端的数据
1 2 3 4 5 6 7 8 HTTP/1.1 200 OK\r\n Server: Tengine\r\n Content-Type: text/html; charset=UTF-8\r\n Transfer-Encoding: chunked\r\n Connection: keep-alive\r\n Date: Fri, 23 Nov 2018 02:01:05 GMT\r\n \r\n <!DOCTYPE html><html lang=“en”> …</html>
2、响应状态码
响应状态码:用于表示web服务器响应状态的3位数字代码
状态码
说明
200
请求成功
307
重定向
400
请求地址或参数有误
404
请求资源在服务器不存在
500
服务器内部源代码出现错误
六、静态Web服务器开发
静态Web服务器:可以为发出请求的浏览器提供静态文档的程序
1. 搭建自带的静态Web服务器
终端进入指定静态文件的目录
命令:python3 -m http.server 端口号
(-m表示运行包里面的模块,端口号默认是8000)
2. 搭建静态Web服务器代码示例 1、返回固定页面数据
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 34 35 36 37 import socketif __name__ == '__main__' : tcp_server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) tcp_server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True ) tcp_server_socket.bind(("192.168.0.101" , 9090 )) tcp_server_socket.listen(128 ) while True : new_socket, ip_port = tcp_server_socket.accept() recv_client_data = new_socket.recv(4096 ) recv_client_content = recv_client_data.decode("utf-8" ) print (recv_client_content) with open ("static/index.html" , "rb" ) as file: file_data = file.read() response_line = "HTTP/1.1 200 OK\r\n" response_header = "Server: PWS1.0\r\n" response_body = file_data response_data = (response_line + response_header + "\r\n" ).encode("utf-8" ) + response_body new_socket.send(response_data) new_socket.close()
2、返回指定页面数据
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 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 import socketdef main (): tcp_server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) tcp_server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True ) tcp_server_socket.bind(("192.168.0.101" , 9090 )) tcp_server_socket.listen(128 ) while True : new_socket, ip_port = tcp_server_socket.accept() recv_client_data = new_socket.recv(4096 ) if len (recv_client_data) == 0 : print ('关闭浏览器了' ) new_socket.close() return recv_client_content = recv_client_data.decode("utf-8" ) print (recv_client_content) request_list = recv_client_content.split(' ' ,maxsplit=2 ) request_path = request_list[1 ] print (request_path) if request_path == '/' : request_path = '/index.html' try : with open ("static" +request_path, "rb" ) as file: file_data = file.read() except Exception as e: response_line = 'HTTP/1.1 404 Not Found\r\n' response_header = 'Server:PWS1.0\r\n' with open ('static/error.html' ,'rb' ) as file: file_data = file.read() response_body = file_data response_data = (response_line + response_header + "\r\n" ).encode("utf-8" ) + response_body new_socket.send(response_data) else : response_line = "HTTP/1.1 200 OK\r\n" response_header = "Server: PWS1.0\r\n" response_body = file_data response_data = (response_line + response_header + "\r\n" ).encode("utf-8" ) + response_body new_socket.send(response_data) finally : new_socket.close() if __name__ == '__main__' : main()
3、返回指定页面数据-多任务
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 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 import socketimport threadingdef handle_client_request (new_socket ): recv_client_data = new_socket.recv(4096 ) if len (recv_client_data) == 0 : print ('关闭浏览器了' ) new_socket.close() return recv_client_content = recv_client_data.decode("utf-8" ) print (recv_client_content) request_list = recv_client_content.split(' ' , maxsplit=2 ) request_path = request_list[1 ] print (request_path) if request_path == '/' : request_path = '/index.html' try : with open ("static" + request_path, "rb" ) as file: file_data = file.read() except Exception as e: response_line = 'HTTP/1.1 404 Not Found\r\n' response_header = 'Server:PWS1.0\r\n' with open ('static/error.html' , 'rb' ) as file: file_data = file.read() response_body = file_data response_data = (response_line + response_header + "\r\n" ).encode("utf-8" ) + response_body new_socket.send(response_data) else : response_line = "HTTP/1.1 200 OK\r\n" response_header = "Server: PWS1.0\r\n" response_body = file_data response_data = (response_line + response_header + "\r\n" ).encode("utf-8" ) + response_body new_socket.send(response_data) finally : new_socket.close() def main (): tcp_server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) tcp_server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True ) tcp_server_socket.bind(("192.168.0.101" , 9090 )) tcp_server_socket.listen(128 ) while True : new_socket, ip_port = tcp_server_socket.accept() sub_thread = threading.Thread(target=handle_client_request,args=(new_socket,),daemon=True ) sub_thread.start() if __name__ == '__main__' : main()
4、返回指定页面数据-多任务&面向对象&动态绑定命令行端口号
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 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 import socketimport threadingimport sysclass HttpWebServer (object ): def __init__ (self,port ): tcp_server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) tcp_server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True ) tcp_server_socket.bind(("192.168.0.101" , port)) tcp_server_socket.listen(128 ) self.tcp_server_socket = tcp_server_socket @staticmethod def handle_client_request (new_socket ): recv_client_data = new_socket.recv(4096 ) if len (recv_client_data) == 0 : print ('关闭浏览器了' ) new_socket.close() return recv_client_content = recv_client_data.decode("utf-8" ) print (recv_client_content) request_list = recv_client_content.split(' ' , maxsplit=2 ) request_path = request_list[1 ] if request_path == '/' : request_path = '/index.html' try : with open ("static" + request_path, "rb" ) as file: file_data = file.read() except Exception as e: response_line = 'HTTP/1.1 404 Not Found\r\n' response_header = 'Server:PWS1.0\r\n' with open ('static/error.html' , 'rb' ) as file: file_data = file.read() response_body = file_data response_data = (response_line + response_header + "\r\n" ).encode("utf-8" ) + response_body new_socket.send(response_data) else : response_line = "HTTP/1.1 200 OK\r\n" response_header = "Server: PWS1.0\r\n" response_body = file_data response_data = (response_line + response_header + "\r\n" ).encode("utf-8" ) + response_body new_socket.send(response_data) finally : new_socket.close() def start (self ): while True : new_socket, ip_port = self.tcp_server_socket.accept() sub_thread = threading.Thread(target=self.handle_client_request, args=(new_socket,), daemon=True ) sub_thread.start() def main (): print (sys.argv) if len (sys.argv) != 2 : print ('执行命令如下:python3 xxx.py 9090' ) return if not sys.argv[1 ].isdigit(): print ('端口号格式为数字' ) return port = int (sys.argv[1 ]) web_server = HttpWebServer(port) web_server.start() if __name__ == '__main__' : main()