手动实现一个简单的 HTTP 请求

news2024/11/15 18:30:29

本文我们通过 Socket,写一个 HTTP 协议,直观的感受一下上篇文章中的请求和响应。

定义 socket server

通过上篇文章,我们知道 HTTP 协议底层是通过 Socket 实现的,所以我们先通过 socket 定义一个 server


import socket

#初始化 socke
sock=socket.socket()
#绑定 地址
sock.bind(('127.0.0.1',8081))

#在 sock.listen(5) 中,参数 5 表示最多可以排队等待处理的连接数量为 5。
# 如果有更多的连接请求到达,超过该数量的连接将被拒绝。
sock.listen(5)
while True:
    #接受客户端请求
    conn,addr=sock.accept()
    data=conn.recv(1024)
    print('客户端的请求数据\r\n',data.decode('utf-8'))
    print("打印完毕=====")
    #响应客户端的请求
    conn.send(b'Hello world')
    conn.close()

在 PyCharm 中执行这段代码后,通过浏览器访问 http://127.0.0.1:8081/
Sever 端 PyCharm 打印结果

客户端的请求数据
GET / HTTP/1.1
Host: 127.0.0.1:8081
Connection: keep-alive
sec-ch-ua: "Chromium";v="122", "Not(A:Brand";v="24", "Google Chrome";v="122"
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "macOS"
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Sec-Fetch-Site: none
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Accept-Encoding: gzip, deflate, br, zstd
Accept-Language: en-US,en;q=0.9,zh-CN;q=0.8,zh;q=0.7

打印完毕=====

分析客户端请求参数-GET请求

在上篇文章中我们讲到 HTTP 协议在发送请求的时候,必须要包含请求行、请求头、请求体。这是浏览器帮我们组织好的。
此处的请求行为

GET / HTTP/1.1

请求头为:

Host: 127.0.0.1:8081
Connection: keep-alive
sec-ch-ua: "Chromium";v="122", "Not(A:Brand";v="24", "Google Chrome";v="122"
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "macOS"
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Sec-Fetch-Site: none
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Accept-Encoding: gzip, deflate, br, zstd
Accept-Language: en-US,en;q=0.9,zh-CN;q=0.8,zh;q=0.7

请求体为:


之所以为空,是因为 GET 请求没有请求体。

分析客户端请求参数-PUT请求

首先通过 python request 包发送 put 请求,因为请求必须要包括请求行、请求头以及请求体,所以 python request 模板会帮我们组织好。

import requests

data={"username":"test","password":"<PASSWORD>"}
respone=requests.post("http://127.0.0.1:8081",json=data)
print(respone)

Sever 端 PyCharm打印结果

客户端的请求数据
POST / HTTP/1.1
Host: 127.0.0.1:8081
User-Agent: python-requests/2.31.0
Accept-Encoding: gzip, deflate, br, zstd
Accept: */*
Connection: keep-alive
Content-Length: 46
Content-Type: application/json

{"username": "test", "password": "<PASSWORD>"}
打印完毕=====

此处的请求行为:

POST / HTTP/1.1

请求头为:

Host: 127.0.0.1:8081
User-Agent: python-requests/2.31.0
Accept-Encoding: gzip, deflate, br, zstd
Accept: */*
Connection: keep-alive
Content-Length: 46
Content-Type: application/json

请求体为:

{"username": "test", "password": "<PASSWORD>"}

服务端响应参数

通过浏览器访问 http://127.0.0.1:8081/ 时,虽然 server 端接受到请求了,也给浏览器反回了 hello world 但浏览器仍然报错了

另外当我们通过 python request 发送 put 请求时,同样 server 端接受到请求了,也返回了 hello world 但 request 程序仍然报错了

Traceback (most recent call last):
  File "/Users/isx/opt/anaconda3/lib/python3.11/site-packages/urllib3/connectionpool.py", line 791, in urlopen
    response = self._make_request(
               ^^^^^^^^^^^^^^^^^^^
  File "/Users/isx/opt/anaconda3/lib/python3.11/site-packages/urllib3/connectionpool.py", line 537, in _make_request
    response = conn.getresponse()
               ^^^^^^^^^^^^^^^^^^
  File "/Users/isx/opt/anaconda3/lib/python3.11/site-packages/urllib3/connection.py", line 461, in getresponse
    httplib_response = super().getresponse()
                       ^^^^^^^^^^^^^^^^^^^^^
  File "/Users/isx/opt/anaconda3/lib/python3.11/http/client.py", line 1390, in getresponse
    response.begin()
  File "/Users/isx/opt/anaconda3/lib/python3.11/http/client.py", line 325, in begin
    version, status, reason = self._read_status()
                              ^^^^^^^^^^^^^^^^^^^
  File "/Users/isx/opt/anaconda3/lib/python3.11/http/client.py", line 307, in _read_status
    raise BadStatusLine(line)
http.client.BadStatusLine: Hello world

这是为什么?
上篇文章中,我们也讲过,服务端的响应也必须要包括响应行、响应头以及响应体,而我们写的 sever 中代码,赵括响应体,所以浏览器和 python request 包会报错。

#响应客户端的请求
conn.send(b'Hello world') 

我们遵循服务端的响应也必须要包括响应行、响应头以及响应体这个要求,改进 server 代码

import socket

sock=socket.socket()

sock.bind(('127.0.0.1',8081))
#在 sock.listen(5) 中,参数 5 表示最多可以排队等待处理的连接数量为 5。
# 如果有更多的连接请求到达,超过该数量的连接将被拒绝。
sock.listen(5)
while True:
    conn,addr=sock.accept()
    data=conn.recv(1024)
    print('客户端的请求数据\r\n',data.decode('utf-8'))
    print("打印完毕=====")

    conn.send(b'HTTP/1.1 200 OK \r\nDate: Tue, 02 Mar 2024 12:00:00 GMT\r\nServer: Apache/2.4.6 (CentOS) OpenSSL/1.0.2k-fips\r\nContent-Type: text/plain\r\nHello world')
    conn.close()

扩展

content-type

content-type 是请求头以及响应头中最重要的参数,它可以分别告诉客户端和服务端该如何处理请求体或者响应体中的参数。举个例子:
server代码

import socket

sock=socket.socket()

sock.bind(('127.0.0.1',8081))
#在 sock.listen(5) 中,参数 5 表示最多可以排队等待处理的连接数量为 5。
# 如果有更多的连接请求到达,超过该数量的连接将被拒绝。
sock.listen(5)
while True:
    conn,addr=sock.accept()
    data=conn.recv(1024)
    print('客户端的请求数据\r\n',data.decode('utf-8'))
    print("打印完毕=====")

    conn.send(b'HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\n\r\n{"username": "test", "password": "<PASSWORD>"}')
    conn.close()

为了更好的呈现响应的结果,这个我们借助 postman 工具。当 Content-Type: text/plain,postman 接受服务端返回的数据类型为 text

当 Content-Type:application/json 时,postman 服务端返回的数据类型为 json

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1484190.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

蓝桥杯备战刷题four(自用)

1.砝码称重 #include <iostream> #include <vector> using namespace std; const int N110; const int M100010; int w[N]; int n; int f[N][M]; int m; int ans; //f[i][j]表示到第i个砝码进行放置时的称得的重量为j的方案数 int main() {cin>>n;for(int i1…

JVM 第四部分—垃圾回收相关概念 2

System.gc() 在默认情况下&#xff0c;通过System.gc()或者Runtime.getRuntime().gc()的调用&#xff0c;会显式触发Full GC&#xff0c;同时对老年代和新生代进行回收&#xff0c;尝试释放被丢弃对象占用的内存 然而System.gc()调用附带一个免责声明&#xff0c;无法保证对垃…

Springboot+vue的商业辅助决策系统的设计与实现(有报告)。Javaee项目,springboot vue前后端分离项目

演示视频&#xff1a; Springbootvue的商业辅助决策系统的设计与实现&#xff08;有报告&#xff09;。Javaee项目&#xff0c;springboot vue前后端分离项目 项目介绍&#xff1a; 本文设计了一个基于Springbootvue的前后端分离的商业辅助决策系统的设计与实现&#xff0c;采…

前端的文字的字体应该如何设置

要设置文字的字体&#xff0c;在CSS中使用font-family属性。这个属性可以接受一个或多个字体名称作为其值&#xff0c;浏览器会按照列表中的顺序尝试使用这些字体渲染文本。如果第一个字体不可用&#xff0c;浏览器会尝试使用列表中的下一个字体&#xff0c;依此类推。 字体设…

6.CVAT——属性注释模式

文章目录 1. 属性注释模式&#xff08;基础&#xff09;2. 属性标注模式&#xff08;高级&#xff09; 1. 属性注释模式&#xff08;基础&#xff09; 属性注释模式下可用的使用示例和基本操作。 在此模式下&#xff0c;您可以使用键盘在对象和框架之间快速导航来编辑属性。打…

【python】`assert`断言语句

assert是一个断言语句&#xff0c;用于在代码中检查某个条件是否为真。 如果条件为假&#xff0c;将触发AssertionError 异常&#xff0c;从而指示存在错误。

Java 网络面试题解析

1. Http 协议的状态码有哪些&#xff1f;含义是什么&#xff1f;【重点】 200&#xff1a;OK&#xff0c;客户端请求成功。 301&#xff1a;Moved Permanently&#xff08;永久移除&#xff09;&#xff0c;请求的URL已移走。Response中应该包含一个Location URL&#xff0c;…

Vue3 条件渲染 v-if

v-if 指令&#xff1a;用于控制元素的显示或隐藏。 执行条件&#xff1a;当条件为 false 时&#xff0c;会将元素从 DOM 中删除。 应用场景&#xff1a;适用于显示隐藏切换频率较低的场景。 语法格式&#xff1a; <div v-if"数据">内容</div> 基础用…

模拟服务器响应的测试框架:moco

第1章&#xff1a;引言 大家好&#xff0c;我是小黑&#xff0c;在这篇博客中&#xff0c;咱们要聊聊Moco测试框架。这个框架&#xff0c;可不是一般的小伙伴&#xff0c;它在模拟服务器响应这块儿&#xff0c;可是有不少看家本领。 首先&#xff0c;Moco是啥呢&#xff1f;简…

彻底搞懂回溯算法(例题详解)

目录 什么是回溯算法&#xff1a; 子集问题&#xff1a; 子集问题II(元素可重复但不可复选): 组合问题&#xff1a; 组合问题II(元素可重复但不可复选): 排列问题&#xff1a; 排列问题II(元素可重复但不可复选): 什么是回溯算法&#xff1a; 「回溯是递归的副产品&…

全球十大正规伦敦金交易平台app软件最新排名(综合版)

伦敦金作为当前国际市场中较为成熟、灵活的投资产品自然备受青睐&#xff0c;但投资者在选择交易软件时&#xff0c;应该尽量选择在行业内排名较高&#xff0c;口碑较好的平台&#xff0c;这样才能获得可靠的投资服务。刚开始不太懂得如何选择伦敦金软件的时候&#xff0c;投资…

SpringBoot原理-配置优先级(黑马学习笔记)

配置优先级 在我们前面的课程当中&#xff0c;我们已经讲解了SpringBoot项目当中支持的三类配置文件&#xff1a; ● application.properties ● application.yml ● application.yaml 在SpringBoot项目当中&#xff0c;我们要想配置一个属性&#xff0c;可以通过这三种方…

手写模拟器,解放双手!效果炸裂的生产工具

手写模拟器是一款基于Handright的仿手写图片生成软件&#xff0c;可以让你的电脑和手机也能写出漂亮的手写字&#xff0c;你只需要输入你想要写的内容&#xff0c;选择你喜欢的字体和背景&#xff0c;就可以生成一张高仿真的手写图片&#xff0c;用于各种场合&#xff0c;比如做…

搜索算法(算法竞赛、蓝桥杯)--双向BFS双向奔赴

1、B站视频链接&#xff1a;B18 双向BFS Nightmare_哔哩哔哩_bilibili 题目链接&#xff1a;Problem - 3085 #include <bits/stdc.h> using namespace std; const int N810; int n,m; #define x first #define y second char g[N][N]; //地图 int vis[N][N]; //2表示女…

3.2日学习打卡----初学FastDFS(二)

3.2日学习打卡 目录: 3.2日学习打卡SpringBoot整合FastDFS实战开发文件上传 FastDFS集成Nginx环境搭建 SpringBoot整合FastDFS 由GitHub大牛tobato在原作者YuQing与yuqih发布的JAVA客户端基础上进行了大量重构工作&#xff0c;并于GitHub上发布了FastDFS-Client1.26.5。 主要特…

Java字符串相关类的底层原理

Java字符串相关类的底层原理

MySQL(2/3)

select和别名的使用 主要是用以查询数据 语法&#xff1a;select 字段 from 库名 -- *代表全部字段 select * from student; -- 可以查询多个字段&#xff0c;并使用as起别名&#xff0c;as可以省略 select id as bbb ,name as hhh from student; -- 可以使用函数concat(a,b…

Matlab|【免费】基于合作博弈的综合能源系统利益分配优化调度

目录 主要内容 部分代码 结果一览 下载链接 主要内容 该程序实现的模型为综合能源系统利益分配优化调度&#xff0c;采用合作博弈方法&#xff0c;模型针对IES系统的P2G、电解槽、甲烷反应器、储氢罐、CHP和燃气锅炉等设备进行建模&#xff0c;实现基于合作博弈的…

Stable Cascade-ComfyUI中文生图、图生图、多图融合基础工作流分享

最近 ComfyUI对于Stable Cascade的支持越来越好了一些&#xff0c;官方也放出来一些工作流供参考。 这里简单分享几个比较常用的基础工作流。 &#xff08;如果还没有下载模型&#xff0c;可以先阅读上一篇Stable Cascade升级&#xff0c;现在只需要两个模型&#xff09; &a…

把Anaconda添加进环境变量的方法(解决pip识别不到环境的问题)

找到你的Anaconda的安装根目录 比如我的是在&#xff1a;C:\ProgramData\Anaconda3 那么只需要将以下目录添加进环境变量即可&#xff1a; C:\ProgramData\Anaconda3C:\ProgramData\Anaconda3\ScriptsC:\ProgramData\Anaconda3\Library\binC:\ProgramData\Anaconda3\condabin…