Python进阶---HTTP协议和Web服务器

Python进阶---HTTP协议和Web服务器

一、HTTP协议

1. HTTP 协议的介绍

2. HTTP 协议的作用

3. 浏览器访问web服务器的通信过程

 4. 小结

5.补充

二、URL

1. URL的概念

2. URL的组成

三、HTTP请求报文

1. HTTP 请求报文介绍

2. HTTP GET 请求报文分析

3. HTTP POST 请求报文分析

4.GET和POST请求对比效果图:

 四、HTTP响应报文

1. HTTP响应报文分析

2. HTTP 状态码介绍

五、Web服务器

1. 什么是Web服务器?

2. Web服务器 和 非Web服务器 的区别

3. Web服务器-示例代码

4. 小结

六、Web服务器--进阶

1、在页面上显示文字

2、显示网页(根据网志不同显示不同的网页)

3、异常处理

4、显示图片


一、HTTP协议

提到协议,大家并不陌生。

大家都在遵守的规定就是协议,HTTP协议的目的是为了传输多种类型的数据。

1. HTTP 协议的介绍

        HTTP 协议的全称是(HyperText Transfer Protocol),翻译过来就是超文本传输协议。

        超文本是超级文本的缩写,是指超越文本限制或者超链接,比如:图片、音乐、视频、超链接等等都属于超文本。

        HTTP 协议的制作者是蒂姆·伯纳斯-李,1991年设计出来的,HTTP 协议设计之前目的是传输网页数据的,现在允许传输任意类型的数据。

        传输 HTTP 协议格式的数据是基于 TCP 传输协议的,发送数据之前需要先建立连接。

2. HTTP 协议的作用

        它规定了浏览器和 Web 服务器通信数据的格式,

        也就是说浏览器和web服务器通信需要使用http协议。

3. 浏览器访问web服务器的通信过程

        通信效果图:

Python进阶---HTTP协议和Web服务器_第1张图片

 4. 小结

  • HTTP协议是一个超文本传输协议
  • HTTP协议是一个基于TCP传输协议传输数据的
  • HTTP协议规定了浏览器和 Web 服务器通信数据的格式

5.补充

        1.  数据在网络中传输

  • 确定数据的传输形式( TCP  UDP )

  • 确定数据的形式( HTTP )

    • 一个数据相当于一个数据包

      • 第一行是什么数据

      • 第二行是什么数据

      • …..

        2.  c/s模型和b/s模型

        c/s模型 ==> 客户端 /服务端 这样的形式

                不需要遵循http协议的

        b/s模型 ==> 浏览器/服务端 这样的形式

                需要遵循http协议的

二、URL

1. URL的概念

        URL的英文全拼是(Uniform Resoure Locator),表达的意思是统一资源定位符,通俗理解就是网络资源地址,也就是我们常说的网址。

        URL就是网络资源的地址,简称网址,通过URL能够找到网络中对应的资源数据。

2. URL的组成

        URL的样子:CSDN - 专业开发者社区https://www.csdn.net/

  • URL的组成部分:
  1. 协议部分: https://、http://、ftp://
  2. 域名部分: news.163.com
  3. 资源路径部分: /18/1122/10/E178J2O4000189FH.html
  •  域名:   域名就是IP地址的别名,它是用点进行分割使用英文字母和数字组成的名字,使用域名目的就是方便的记住某台主机IP地址。

三、HTTP请求报文

1. HTTP 请求报文介绍

      HTTP最常见的请求报文有两种:

  1. GET 方式的请求报文
  2. POST 方式的请求报文

        说明:

  • GET: 获取web服务器数据
  • POST: 向web服务器提交数据

2. HTTP GET 请求报文分析

GET 请求报文说明:

---- 请求行 ----
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; # 登录用户的身份标识

---- 空行 ----

GET 请求原始报文说明:

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  (请求头信息后面还有一个单独的’\r\n’不能省略)



说明:每项数据之间使用:\r\n

3. HTTP POST 请求报文分析

POST 请求报文说明:

---- 请求行 ----
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 # 请求参数

POST 请求原始报文说明:

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



说明:每项数据之间使用:\r\n

4.GET和POST请求对比效果图:

Python进阶---HTTP协议和Web服务器_第2张图片

 四、HTTP响应报文

1. HTTP响应报文分析

        响应报文说明:

--- 响应行/状态行 ---
HTTP/1.1 200 OK # HTTP协议版本 状态码 状态描述
--- 响应头 ---
Server: Tengine # 服务器名称
Content-Type: text/html; charset=UTF-8 # 内容类型
Transfer-Encoding: chunked # 发送给客户端内容不确定内容长度,发送结束的标记是0\r\n, Content-Length表示服务端确定发送给客户端的内容大小,但是二者只能用其一。
Connection: keep-alive # 和客户端保持长连接
Date: Fri, 23 Nov 2018 02:01:05 GMT # 服务端的响应时间
--- 空行 ---
--- 响应体 ---
 … # 响应给客户端的数据

        原始响应报文说明:

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(响应头信息后面还有一个单独的’\r\n’不能省略)
 …


每项数据之间使用:\r\n

2. HTTP 状态码介绍

HTTP 状态码是用于表示web服务器响应状态的3位数字代码。

状态码 说明
200 请求成功
307 重定向
400 错误的请求,请求地址或者参数有误
404 请求资源在服务器不存在
500 服务器内部源代码出现错误

五、Web服务器

1. 什么是Web服务器?

Web服务器可以解析HTTP协议。当Web服务器接收到一个HTTP请求,会返回一个HTTP响应,例如送回一个HTML页面.

简单说Web服务器可以和浏览器进行通信. 而有的服务器是不能和浏览器进行通讯的, 例如我们之前写的服务器. 

 Web服务器:

Python进阶---HTTP协议和Web服务器_第3张图片

2. Web服务器 和 非Web服务器 的区别

浏览器发送的请求数据是符合http协议的数据格式要求的, 平时在使用浏览器的时候我们也常常访问网站, 而这些网站的网址大多数是以http或者https开头, 这就是要求符合http协议的要求.

Web服务器可以和浏览器进行通信. 非Web服务器不能和浏览器进行通讯的主要原因也在于http协议, Web服务器可以处理http协议的请求报文, 也可以发送http协议的响应报文, 因此Web服务器可以和浏览器通信.

3. Web服务器-示例代码

知道Web服务器非Web服务器的区别, 那么实现Web服务器也就简单了.

Web服务器要求

  • 可以处理http协议请求报文
  • 可以发送http协议响应报文
# 导入模块
import socket

# 创建tcp服务端套接字
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(("", 8989))
# 设置监听
# 128:最大等待建立连接的个数, 提示: 目前是单任务的服务端,同一时刻只能服务与一个客户端,后续使用多任务能够让服务端同时服务与多个客户端,
# 不需要让客户端进行等待建立连接
# listen后的这个套接字只负责接收客户端连接请求,不能收发消息,收发消息使用返回的这个新套接字来完成
tcp_server_socket.listen(128)
# 等待客户端建立连接的请求, 只有客户端和服务端建立连接成功代码才会解阻塞,代码才能继续往下执行
# 1. 专门和客户端通信的套接字: service_client_socket
# 2. 客户端的ip地址和端口号: ip_port
service_client_socket, ip_port = tcp_server_socket.accept()
# 代码执行到此说明连接建立成功
print("客户端的ip地址和端口号:", ip_port)
# 接收客户端发送的数据, 这次接收数据的最大字节数是1024
recv_data = service_client_socket.recv(1024)
# 获取数据的长度
recv_data_length = len(recv_data)
print("接收数据的长度为:", recv_data_length)
# 对二进制数据进行解码
recv_content = recv_data.decode("utf8")
print("接收客户端的数据为:", recv_content)

# 解析http协议请求报文数据
# 获取请求行
request_line = recv_content.split("\n")[0]
# 获取请求路径
request_path = request_line.split(" ")[1]
print("客户端的请求路径为:", request_path)

# 符合http协议的响应报文
# 响应行
response_line = "HTTP / 1.1 200 OK\r\n"
# 响应头
response_header = "Server: Tengine\r\n"
# 响应体
response_body = "

123

" # 组成响应报文 response_data = response_line + response_header + "\r\n" + response_body # 发送数据给客户端 service_client_socket.send(response_data.encode()) # 关闭服务与客户端的套接字, 终止和客户端通信的服务 service_client_socket.close() # 关闭服务端的套接字, 终止和客户端提供建立连接请求的服务 tcp_server_socket.close()

我们的Web服务器一旦处理一个请求之后就会关闭, 也就是说当前服务器只能处理一次请求. 下面我们通过while循环让服务器处于一直运行的状态, 可以处理多次请求.

Web服务器要求

  • 可以处理多次浏览器的请求
# 导入模块
import socket

# 创建tcp服务端套接字
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(("", 8989))
# 设置监听
# 128:最大等待建立连接的个数, 提示: 目前是单任务的服务端,同一时刻只能服务与一个客户端,后续使用多任务能够让服务端同时服务与多个客户端,
# 不需要让客户端进行等待建立连接
# listen后的这个套接字只负责接收客户端连接请求,不能收发消息,收发消息使用返回的这个新套接字来完成
tcp_server_socket.listen(128)

while True:
    # 等待客户端建立连接的请求, 只有客户端和服务端建立连接成功代码才会解阻塞,代码才能继续往下执行
    # 1. 专门和客户端通信的套接字: service_client_socket
    # 2. 客户端的ip地址和端口号: ip_port
    service_client_socket, ip_port = tcp_server_socket.accept()
    # 代码执行到此说明连接建立成功
    print("客户端的ip地址和端口号:", ip_port)
    # 接收客户端发送的数据, 这次接收数据的最大字节数是1024
    recv_data = service_client_socket.recv(1024)
    # 获取数据的长度
    recv_data_length = len(recv_data)
    print("接收数据的长度为:", recv_data_length)
    # 对二进制数据进行解码
    recv_content = recv_data.decode("utf8")
    print("接收客户端的数据为:", recv_content)

    # 解析http协议请求报文数据
    # 获取请求行
    request_line = recv_content.split("\n")[0]
    # 获取请求路径
    request_path = request_line.split(" ")[1]
    print("客户端的请求路径为:", request_path)

    # 符合http协议的响应报文
    # 响应行
    response_line = "HTTP / 1.1 200 OK\r\n"
    # 响应头
    response_header = "Server: Tengine\r\n"
    # 响应体
    response_body = "

123<\h1>" # 组成响应报文 response_data = response_line + response_header + "\r\n" + response_body # 发送数据给客户端 service_client_socket.send(response_data.encode()) # 关闭服务与客户端的套接字, 终止和客户端通信的服务 service_client_socket.close() # 关闭服务端的套接字, 终止和客户端提供建立连接请求的服务 tcp_server_socket.close()

4. 小结

  1. Web服务器的要求

    • 可以处理http协议请求报文
    • 可以发送http协议响应报文
  2. 响应报文代码

    # 符合http协议的响应报文
    # 响应行
    response_line = "HTTP / 1.1 200 OK\r\n"
    # 响应头
    response_header = "Server: Tengine\r\n"
    # 响应体
    response_body = "

    123<\h1>" # 组成响应报文 response_data = response_line + response_header + "\r\n" + response_body

六、Web服务器--进阶

实际上在完成了Web服务器后, 我们也通过Web服务器向浏览器发送了数据. 而这里我们需要发送的数据是html, 所以只需要把Web服务器发送给浏览器的数据改成为html就可以了。

1、在页面上显示文字

import socket

# 创建socket
tcp_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 设置端口复用
tcp_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)
# 绑定
tcp_socket.bind(("", 8080))
# 设置监听
tcp_socket.listen(128)
# 接受链接请求
client_socket, client_addr = tcp_socket.accept()

# 接受数据
recv_data = client_socket.recv(1024)
print("接受的数据:", recv_data.decode("utf8"))

# 发送数据
# 组合一个符合http响应报文格式的数据
response_line = "HTTP/1.1 200 OK\n"
response_header = "server:py1.0\n"
response_body = "

你好,我是木易巷!

" # 组成一个响应报文 response_data = response_line + response_header + "\n" + response_body client_socket.send(response_data.encode("gbk")) # 关闭 client_socket.close() tcp_socket.close()

2、显示网页(根据网志不同显示不同的网页)

"""
1. 区分网址的不同
2. 根据不同的网址返回不同的页面
"""

import socket

# 创建socket
tcp_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 设置端口复用
tcp_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)
# 绑定
tcp_socket.bind(("", 8082))
# 设置监听
tcp_socket.listen(128)

while True:
    # 接受链接请求
    client_socket, client_addr = tcp_socket.accept()
    # 接受数据
    recv_data = client_socket.recv(1024)
    # 解码后编程字符串类型的数据
    recv_data = recv_data.decode("utf8")
    # 因为要获取请求路径所以对字符串进行分割
    request_path = recv_data.split(' ')[1]
    print("请求路径为:", request_path)
    # 如果浏览器输入的是 127.0.0.1:8080/aaa.html
    # open(./html/aaa.html)
    f = open(f"html{request_path}","rb")
    file_data = f.read()
    f.close()
    # 组成响应报文
    response_line = "HTTP/1.1 200 OK\n"
    response_header = "server:py1.0\n"
    response_body = file_data
    # 组成一个响应报文
    response_data = response_line + response_header + "\n"

    client_socket.send(response_data.encode("utf8")+ response_body)
    client_socket.close()

3、异常处理

"""
1. 区分网址的不同
2. 根据不同的网址返回不同的页面
"""

import socket

# 创建socket
tcp_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 设置端口复用
tcp_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)
# 绑定
tcp_socket.bind(("", 8080))
# 设置监听
tcp_socket.listen(128)

while True:
    # 接受链接请求
    client_socket, client_addr = tcp_socket.accept()
    # 接受数据
    recv_data = client_socket.recv(1024)
    # 解码后编程字符串类型的数据
    recv_data = recv_data.decode("utf8")
    # 因为要获取请求路径所以对字符串进行分割
    request_path = recv_data.split(' ')[1]
    print("请求路径为:", request_path)

    try:
        # 如果浏览器输入的是 127.0.0.1:8080/aaa.html
        # open(./html/aaa.html)
        f = open(f"html{request_path}", "r", encoding="utf8")
        file_data = f.read()
        f.close()
    except Exception as e:
        # 组成响应报文
        response_line = "HTTP/1.1 200 OK\n"
        response_header = "server:py1.0\n"
        response_body = f"NOT FOUND:{e}"
        # 组成一个响应报文
        response_data = response_line + response_header + "\n" + response_body
        client_socket.send(response_data.encode("utf8"))
    else:
        # 组成响应报文
        response_line = "HTTP/1.1 200 OK\n"
        response_header = "server:py1.0\n"
        response_body = file_data
        # 组成一个响应报文
        response_data = response_line + response_header + "\n" + response_body
        client_socket.send(response_data.encode("utf8"))
    finally:
        client_socket.close()

4、显示图片

"""
1. 区分网址的不同
2. 根据不同的网址返回不同的页面
"""

import socket

# 创建socket
tcp_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 设置端口复用
tcp_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)
# 绑定
tcp_socket.bind(("", 8080))
# 设置监听
tcp_socket.listen(128)

while True:
    # 接受链接请求
    client_socket, client_addr = tcp_socket.accept()
    # 接受数据
    recv_data = client_socket.recv(1024)
    # 解码后编程字符串类型的数据
    recv_data = recv_data.decode("utf8")
    # 因为要获取请求路径所以对字符串进行分割
    request_path = recv_data.split(' ')[1]
    print("请求路径为:", request_path)

    try:
        # 如果浏览器输入的是 127.0.0.1:8080/aaa.html
        # open(./html/aaa.html)
        # rb就是以二进制的形式进行数据的读取
        f = open(f"html{request_path}", "rb")
        file_data = f.read()
        f.close()
    except Exception as e:
        # 组成响应报文
        response_line = "HTTP/1.1 200 OK\n"
        response_header = "server:py1.0\n"
        response_body = f"NOT FOUND:{e}"
        # 组成一个响应报文
        response_data = response_line + response_header + "\n"
        client_socket.send(response_data.encode("utf8") + response_body)
    else:
        # 组成响应报文
        response_line = "HTTP/1.1 200 OK\n"
        response_header = "server:py1.0\n"
        response_body = file_data
        # 组成一个响应报文
        response_data = response_line + response_header + "\n"
        client_socket.send(response_data.encode("utf8") + response_body)
    finally:
        client_socket.close()

注意:

1.代码中的路径问题  文件需要自行创建 可以自己写几个网页实现一下

2.在同一个局域网下,电脑之间可以访问服务器,并可以在浏览器搜索框通过修改路径查看服务器电脑的html文件

你可能感兴趣的:(Python进阶,http,服务器,前端)