http协议以及静态web服务器

HTTP协议介绍

HyperText Transfer Protocol
是浏览器与web服务器通信的格式。
基于TCP协议,浏览器作为客户端,web服务器作为服务端。
因此,通信的时候有下面的流程:

  1. 通过DNS——域名解析服务器将www.baidu.com这样的域名解析成ip地址
  2. 获得百度的ip地址,一般端口号默认成80,浏览器与web服务器请求连接
  3. 客户端根据http协议按照一定格式发送请求
  4. web服务器向自己的数据中请求获取资源
  5. 数据返回资源给web服务器
  6. web服务器按照http协议的格式把自己得到的资源给客户端

URL

Uniform Resource Locator=网址
网址由以下内容组成:

  1. 协议:https://是对http://的加密版。而且http的默认端口号是80,而https的默认端口号是443。
  2. 域名:www.baidu.com
  3. 资源路径
  4. 查询参数部分,一般是?参数1= …&参数2= …,可以没有

浏览器发给web服务器的http请求报文

两种类型:

  • get:获取数据
  • post:提交数据(比如登录的时候发送用户名密码

get请求报文格式

比如baidu.com的:

GET / HTTP/1.1
Host: www.baidu.com
Connection: keep-alive
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.149 Safari/537.36
Sec-Fetch-Dest: document
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,/;q=0.8,application/signed-exchange;v=b3;q=0.9
Sec-Fetch-Site: none
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9
cookie: …

GET / HTTP/1.1是请求行
第一个斜杠表示资源路径,即百度的首页
1.1是HTTP的版本
后面是请求头
Host:如果没有写端口号,就是自动80
Connection: keep-alive指的是请求后,客户端与服务端不断开连接,但是一段时间后,服务端会自动断开连接。
User-Agent: 爬虫中可以根据user-agent进行反爬。指的是如果服务器看到user-agent视感浏览器,就给数据;如果是爬虫,就不给数据。
accept告诉服务端程序自己可以接受的数据类型
accept-encoding告诉服务端自己可以接受的压缩算法
还有一长段cookie:用来标识客户端用户身份,每个人都不一样。
最后是一个空行
而且请求报文每句话最后都要写\r\n,最后必须有一个空行,也要写\r\n。

因此http的get请求报文格式:
1.请求行
2.请求头
3.空行
且每个信息后都要有\r\n。

post请求报文格式

比如登录圆通快递官网失败。
在这里插入图片描述
POST的请求,端口号80。

POST /api/user/login?randValue=7c299c65-8c77-4c3a-b0f5-f1cc9982833f&code=1551&username=…&password=adda HTTP/1.1
Host: ec.yto.net.cn
Connection: keep-alive
Content-Length: 0
Accept: application/json, text/plain, /
source: PC
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.149 Safari/537.36
trace: {“loginSource”:“12”,“terminalModel”:“01”}
Origin: http://ec.yto.net.cn
Referer: http://ec.yto.net.cn/userlogin
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Cookie: …

这些与get是一样的,唯一不同的是多了一个请求体Form data,就是浏览器发送给服务器的用户名密码数据。

因此http的post请求报文格式:
1.请求行
2.请求头
3.空行
4.请求体
且每个信息后都要有\r\n。

post可以没有请求体,但一般都有

web服务器发送给浏览器的http响应报文

比如百度

响应行
HTTP/1.1 200 OK
响应头
Bdpagetype: 2
Bdqid: 0xe2a7978200001d14
Cache-Control: private
Connection: keep-alive
Content-Encoding: gzip
Content-Type: text/html;charset=utf-8
Date: Thu, 20 May 2021 03:20:15 GMT
Expires: Thu, 20 May 2021 03:20:15 GMT
Server: BWS/1.1
Set-Cookie: BDSVRTM=324; path=/
Set-Cookie: BD_HOME=1; path=/
Set-Cookie: H_PS_PSSID=33764_33816_31253_34004_33772_33676_33607_26350_22158; path=/; domain=.baidu.com
Strict-Transport-Security: max-age=172800
Traceid: 1621480815059020980216332189158283943188
X-Ua-Compatible: IE=Edge,chrome=1
Transfer-Encoding: chunked
空行

响应体 给浏览器的数据,html文件

HTTP/1.1 200 OK中的200 OK表示OK的状态码。
transfer-encoding: chunked即服务器发送给客户端的数据不确定长度,但有结束标识0\r\n,或者还有一个参数content-length,是可以确认长度的。
data服务器时间,是格林威治时间,差8小时。
除了这些以及熟悉的,其他都是网站自定义的,需要客户端服务端约定好。
响应体在Response里面:
在这里插入图片描述
每段信息\r\n。

因此http的响应报文格式:
1.响应行
2.响应头
3.空行
4.响应体
且每个信息后都要有\r\n。

HTTP常见状态码

比如前面的响应报文中的200
是服务器返回给客户端自己的状态。
200:成功
307:重定向,请求的网址不提供服务,改成了别的网址。
400:错误的请求,可能是请求中的request headers的请求头的资源地址写错了,也有可能是请求体里面的参数名写错了。
404:请求资源在服务器中不存在
500:服务器崩溃

静态web服务器

为浏览器提供静态文档(不会变的数据)的服务器。

通过cmd搭建静态web服务器

前提:在windows系统上。
打开cmd
首先一定要cd到自己的那堆网页存储的文件夹
然后输入python -m http.server 端口号
即可。
其中输入的地方,很多地方讲要输入python3,我试了好多次都不行,发现改成python后便可以了。
如图:
在这里插入图片描述
然后可以检测一下自己的服务器有没有被创建,在浏览器中输入localhost:端口号,即可访问自己的web服务器。

通过python开发静态web服务器

也就是开发一个TCP服务端程序。

返回固定页面

先把原来的那堆html网页给拖进来。

import socket

if __name__ == '__main__':
    tcp_serve_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    tcp_serve_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)
    tcp_serve_socket.bind(("", 8000))
    tcp_serve_socket.listen(128)
    while True:
        # 等待客户端链接请求,返回新的套接字和客户端ip与客户端端口号
        # 注意,每有一个客户端请求连接,服务端就会创建一个新的套接字与客户端通信,这里这个新的套接字被命名为new_client
        # accept接受链接,并返回新的服务端socket
        new_client, ip_port = tcp_serve_socket.accept()
        print("客户端的ip和端口号为:", ip_port)
        # 注意这里的元组传参格式,只有一个参数不能直接写,要写(new_client,)
        recv_data = new_client.recv(4096)
        print("客户端发送的数据为:", recv_data)

        # 使用with open可以不用写file.close,可以自动关闭
        with open('static/index.html', 'r') as file:
            file_data = file.read()

        # 开始发送index.html
        # 需要弄成http格式
        # 响应行
        response_line = "HTTP/1.1 200 OK\r\n"
        # 响应头
        response_head = "Server: PWS/1.0\r\n"
        # 空行
        # 响应体
        response_body = file_data
        # 拼接
        response = response_line + response_head + '\r\n' + response_body
        # 编码
        response_data = response.encode('utf-8')
        new_client.send(response_data)

        new_client.close()

即不论浏览器想访问哪个网页,都给它index.html的数据。

返回指定页面

首先看一下客户端发送的数据是什么:
在这里插入图片描述
这就是请求报文,里面的grand.html表示了要访问的地址。
前面的b表示是二进制的格式,我们看之前的程序,确实还没有解码,因此应该再加上解码的语句。

import socket

if __name__ == '__main__':
    tcp_serve_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    tcp_serve_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)
    tcp_serve_socket.bind(("", 8000))
    tcp_serve_socket.listen(128)
    while True:
        # 等待客户端链接请求,返回新的套接字和客户端ip与客户端端口号
        # 注意,每有一个客户端请求连接,服务端就会创建一个新的套接字与客户端通信,这里这个新的套接字被命名为new_client
        # accept接受链接,并返回新的服务端socket
        new_client, ip_port = tcp_serve_socket.accept()
        print("客户端的ip和端口号为:", ip_port)
        # 注意这里的元组传参格式,只有一个参数不能直接写,要写(new_client,)
        recv_data = new_client.recv(4096)

        # 解码,这里多试了一下,
        recv_content = recv_data.decode("gbk")
        print("客户端发送的数据为:", recv_content)
        # 如果发来了无意义的数据,为了防止之后分割的时候报错,终止套接字即可
        if len(recv_content) == 0:
            new_client.close()
            continue

        # 获取请求内容,并分割
        request_list = recv_content.split(" ", maxsplit=2)
        # 得到请求的资源路径
        request_path = request_list[1]
        print("请求的路径为:", request_path)
        if request_path == '/':
            request_path = '/index.html'

        # 使用with open可以不用写file.close,可以自动关闭,rb是为了兼容打开图片的请求,打开的数据成了二进制的格式
        with open('static' + request_path, 'rb') as file:
            file_data = file.read()

        # 开始发送请求的页面
        # 需要弄成http格式
        # 响应行
        response_line = "HTTP/1.1 200 OK\r\n"
        # 响应头
        response_head = "Server: PWS/1.0\r\n"
        # 空行
        # 响应体
        response_body = file_data
        # 拼接,因为前面的file_data是二进制,所以其他也要转成二进制才能拼接
        response_data = (response_line + response_head + '\r\n').encode('utf-8') + response_body
        new_client.send(response_data)

        new_client.close()
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值