重新认识HTTP

http请求报文包含三个部分(请求行 + 请求头 + 请求体)

请求行

请求行包含三个内容: method + request-URI + http-version

-- 例如
GET /icwork/? Search = product HTTP/1.1

请求方法

请求方法 作用
get 通过请求URI获得资源
post 用于添加新的资源,用于表单提交
put 用于修改某个内容
delete 删除某个内容
connect 用于代理进行传输例如SSL
options 询问可以执行那些方法
patch 部分文档更该
propfind 查看属性
proppatch 设置属性
mkcol 创建集合
copy 拷贝
move 移动
lock 加锁
unlock 解锁
trace 用于远程诊断服务器
head 类似于get,用于检查对象是否存在用于得到元数据

get方法和post方法

get方法

是在url中说明情请求的资源,比如https://www.baidu.com/con?from=self?_t=1466609839126 其中?后的数据就是请求的数据,并且连接用&,get方法也可以提交表单数据,但是提交的数据在url中,其他人可以通过查看历史记录中的url来获取你提交的数据,这样很不安全

post方法

传输数据不在url中,而在数据段中出现,并且请求头多了Content-Type 和 Content-Length,post提交表单数据的时候比get方法更安全

post方法提交表单和get方法提交表单相比较

  1. get明文传输,信息附加在url上面,get明文传输,post更加安全
  2. get传输有大小限制,应该是3k,post需要制定传输类型
  3. get多用于获取数据,根据get变量的不同调用不同的数据,post多用于提交数据,提交用户输入的数据

get方法和post方法区别

Get是向服务器发索取数据的一种请求,而Post是向服务器提交数据的一种请求
Get是获取信息,而不是修改信息,类似数据库查询功能一样,数据不会被修改
Get请求的参数会跟在url后进行传递,请求的数据会附在URL之后,以?分割URL和传输数据,参数之间以&相连,%XX中的XX为该符号以16进制表示的ASCII,如果数据是英文字母/数字,原样发送,如果是空格,转换为+,如果是中文/其他字符,则直接把字符串用BASE64加密。
Get传输的数据有大小限制,因为GET是通过URL提交数据,那么GET可提交的数据量就跟URL的长度有直接关系了,不同的浏览器对URL的长度的限制是不同的。
GET请求的数据会被浏览器缓存起来,用户名和密码将明文出现在URL上,其他人可以查到历史浏览记录,数据不太安全。在服务器端,用Request.QueryString来获取Get方式提交来的数据
Post请求则作为http消息的实际内容发送给web服务器,数据放置在请求体中,Post没有限制提交的数据。Post比Get安全,当数据是中文或者不敏感的数据,则用get,因为使用get,参数会显示在地址,对于敏感数据和不是中文字符的数据,则用post
POST表示可能修改变服务器上的资源的请求,在服务器端,用Post方式提交的数据只能用Request.Form来获取

请求头

请求头成分

Accept:指浏览器或其他客户可以接爱的MIME文件格式。Servlet可以根据它判断并返回适当的文件格式。
User-Agent:是客户浏览器名称
Host:对应网址URL中的Web名称和端口号。
Accept-Langeuage:指出浏览器可以接受的语言种类,如en或en-us,指英语。
connection:用来告诉服务器是否可以维持固定的HTTP连接。http是无连接的,HTTP/1.1使用Keep-Alive为默认值,这样,当浏览器需要多个文件时(比如一个HTML文件和相关的图形文件),不需要每次都建立连
Cookie:浏览器用这个属性向服务器发送Cookie。Cookie是在浏览器中寄存的小型数据体,它可以记载和服务器相关的用户信息,也可以用来实现会话功能。
Referer:表明产生请求的网页URL。如比从网页/icconcept/index.jsp中点击一个链接到网页/icwork/search,在向服务器发送的GET/icwork/search中的请求中,Referer是http://hostname:8080/icconcept/index.jsp。这个属性可以用来跟踪Web请求是从什么网站来的。
User-Agent:是客户浏览器名称。
Content-Type:用来表名request的内容类型。可以用HttpServletRequest的getContentType()方法取得。
Accept-Charset:指出浏览器可以接受的字符编码。英文浏览器的默认值是ISO-8859-1.
Accept-Encoding:指出浏览器可以接受的编码方式。编码方式不同于文件格式,它是为了压缩文件并加速文件传递速度。浏览器在接收到Web响应之后先解码,然后再检查文件格式。

get方法请求头

Accept:image/webp,image/*,*/*;q=0.8
Accept-Encoding:gzip, deflate, sdch, br
Accept-Language:en-US,en;q=0.8
Connection:keep-alive
Cookie:PSTM=1466499789; BAIDUID=D3A617EE01FFA9DB9B7E3E5F0D3A01EE:FG=1; BIDUPSID=4AA34EC11075CB66B8BC9792DD422B6F; BDUSS=VCc1M0cVQtYnFGfmxTUW5kVTUydnBZUmhiWFRXbnRlMnpIdWV2ODVxNHZ1WkZYQVFBQUFBJCQAAAAAAAAAAAEAAADkEA1ZtPO3rMfRt6zH0cfRAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC8salcvLGpXdz; BD_HOME=1; BD_UPN=123353; BDRCVFR[feWj1Vr5u3D]=I67x6TjHwwYf0; BD_CK_SAM=1; H_PS_PSSID=19292_18286_1458_20318_18241_20369_17942_20388_19690_20417_18560_17001_15560_12277_20253; BDSVRTM=0
Host:www.baidu.com
Referer:https://www.baidu.com/s?wd=http%20%E8%AF%B7%E6%B1%82%E6%95%B0%E6%8D%AE%E7%9A%84%E6%95%B0%E6%8D%AE%E5%8C%85%E6%A0%BC%E5%BC%8F&rsv_spt=1&rsv_iqid=0x9b746a8000022af9&issp=1&f=8&rsv_bp=1&rsv_idx=2&ie=utf-8&rqlang=cn&tn=baiduhome_pg&rsv_enter=1&oq=http%20%E8%AF%B7%E6%B1%82%E6%96%B9%E5%BC%8Fpost%20url%E6%A0%BC%E5%BC%8F&rsv_t=59fb7cEn5xgK8JFpqQ7F7coy6k6dn5sGpEMj1cDM4oMoy0TGArJ2l3fxOqy6F9lXoqoi&inputT=7936&rsv_pq=ca5859d100027005&rsv_sug3=73&rsv_sug1=12&rsv_sug7=100&rsv_sug2=0&rsv_sug4=32020
User-Agent:Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.79 Safari/537.36

post方法请求头

Accept:*/*
Accept-Encoding:gzip, deflate, br
Accept-Language:en-US,en;q=0.8
Authorization:Basic WkEtMTE0MjcyNjAyMDY=
Connection:keep-alive
Content-Length:666
Content-Type:application/json
Host:zhihu-web-analytics.zhihu.com
Origin:http://www.zhihu.com
Referer:http://www.zhihu.com/question/41690822
User-Agent:Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.79 Safari/537.36
Request Payload
view source

相比之下多了content-Type 和 Content-Length

Content-Type:表示的是请求报文体的 MIME 类型

注:GET的请求消息体是空的 所以不需要指定消息体的MIME类型

Content-Length:表示的是 post的数据的长度

举例说明

1 GET/sample.jspHTTP/1.1
2 Accept:image/gif.image/jpeg,*/*
3 Accept-Language:zh-cn
4 Connection:Keep-Alive
5 Host:localhost
6 User-Agent:Mozila/4.0(compatible;MSIE5.01;Window NT5.0)
7 Accept-Encoding:gzip,deflate
8
9 username=ccsvip&password=1234

第一行为http请求行,包含方法,URI 和http版本

1-7为请求头,包含浏览器,主机,接受的编码方式和压缩方式

第8行表示一个空行 表示请求头结束 这个空行是必须的

第9行是数据体,比如是需要查询的信息。

请求体

http响应由三个部分组成分别是状态行,响应头,响应正文

状态行

状态行是由:HTTP-Version + Status-Code + Reason-Phrase

比如:HTTP/1.1 200 ok
分别表示:http版本 + 状态码 + 状态代码的文本描述

响应状态码

状态码类型 表达意义
1xx 指示信息–表示请求已接收,继续处理
2xx 成功–表示请求已被成功接收、理解、接受
3xx 重定向–要完成请求必须进行更进一步的操作。
4xx 客户端错误–请求有语法错误或请求无法实现。
5xx 服务器端错误–服务器未能实现合法的请求。

响应头

响应头:包含服务器类型,日期,长度,内容类型等

Server:Apache Tomcat/5.0.12
Date:Mon,6Oct2003 13:13:33 GMT
Content-Type:text/html
Last-Moified:Mon,6 Oct 2003 13:23:42 GMT
Content-Length:112

响应正文

响应正文响应正文就是服务器返回的HTML页面,HTTP响应头与响应正文之间也必须以空行分隔

正文部分的MIME类型:HTTP请求及响应的正文部分可以是任意格式的数据,如何保证接收方能看得懂发送方发送的正文数据呢?HTTP协议采用MIME协议来规范正文的数据格式。

文件扩展名 MIME类型
.bin .exe .o .a .z application/octet-stream
.pdf application/pdf
.zip application/zip
.tar application/x-tar
.gif image/gif
.jpg .jpeg image/jpeg
.htm .html text/html
.text .c .h .txt .java text/plain
.mpg .mpeg video/mpeg
.xml application/xml
表单上传文件 multipart/form-data
<form>标签的enctype属性:用于指定表单数据的MIME类型,取值为multipart/form-data,表示表单数据为复合类型的数据,包含多个子部分。

手写一个web框架

如果需要响应中文字符,需要按下面的格式

f'HTTP/1.1 200 OK\r\nContent-Type: text/plain; charset=utf-8\r\n\r\n{response_body}'

浏览器作为客户端进行

第一版

from socket import *

while True:
server = socket()
PORT = 8080
IP = 'localhost'
server.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
server.bind((IP, PORT))
server.listen()
conn, addr = server.accept()
try:
content = conn.recv(1024)
print(f"收到来自客户端的消息:\n{content.decode()}")
response_body = "这是来自服务端的消息,你好,我是小满!"
response = f'HTTP/1.1 200 OK\r\nContent-Type: text/plain; charset=utf-8\r\n\r\n{response_body}'
conn.send(response.encode())
finally:
conn.close()
server.close()

第二版

基于不同的路径地址返回不同的结果

from socket import *

while True:
server = socket()
PORT = 8080
IP = 'localhost'
server.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
server.bind((IP, PORT))
server.listen()
conn, addr = server.accept()
try:
content = conn.recv(1024).decode()
print(f"收到来自客户端的消息:\n{content}")
# 获取到请求的路径
path = content.split()[1]
if path == '/login':
response_body = "你好小满,我是服务器!"
elif path == "/register":
response_body = "小满,您已经成功注册"
else:
response_body = "404 Error"
response = f'HTTP/1.1 200 OK\r\nContent-Type: text/plain; charset=utf-8\r\n\r\n{response_body}'
conn.send(response.encode())
finally:
conn.close()
server.close()

打印请求信息

GET /login HTTP/1.1
Host: 127.0.0.1:8080
Connection: keep-alive
Cache-Control: max-age=0
sec-ch-ua: "Chromium";v="122", "Not(A:Brand";v="24", "Google Chrome";v="122"
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "Windows"
DNT: 1
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) 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: zh-CN,zh;q=0.9,en;q=0.8

第三版

基于wsgiref模块搭建web框架,不需要自己手写,这个模块是python自带的模块,直接使用就行了。

from wsgiref import simple_server

def register():
return '小满,您已经注册成功啦!' def login():
return '你好!小满,您已经成功登录啦!' def other():
return '404 page not found' path_dict = {
'/login': login,
'/register': register
} def run(request, response):
"""
:param request: 请求相关的数据
:param response: 响应相关的数据
:return: 返回给客户端的展示数据
"""
# request 得到的是客户端发送来的字典数据
# 路径存放在这个字典的 PATH_INFO 这个键里面,我们把它取到就可以根据不同路径进行不同的处理了
path = request.get('PATH_INFO') # 此处是固定的写法,不需要纠结
# 列表内如果不这样写,中文会乱码的
response('200 OK', [('Content-Type', 'text/plain; charset=utf-8')]) try:
if path in path_dict:
data = path_dict[path]()
return [data.encode()]
else:
return [other().encode()]
except KeyboardInterrupt:
return ['服务器已断开连接'.encode()] if __name__ == '__main__':
IP = '127.0.0.1'
PORT = 8088
server = simple_server.make_server(IP, PORT, run)
print('\033[31m服务器已建立,等待客户端连接中。。\033[0m')
server.serve_forever()

第四版

模块化,在当前项目创建两个文件夹urlsviews

urls:存放功能函数字典,字典里面存放客户端请求的对应路径,以及路径运行的处理函数内存地址

views:路径对应的功能函数,即业务逻辑的编写

# urls.py
import views path_dict = {
'/login': views.login,
'/register': views.register
}
# views.py
def register():
return '小满,您已经注册成功啦!' def login():
return '你好!小满,您已经成功登录啦!' def other():
return '404 page not found'
# 主函数
from wsgiref import simple_server
import views
import urls def run(request, response):
path = request.get('PATH_INFO')
response('200 OK', [('Content-Type', 'text/plain; charset=utf-8')]) try:
if path in urls.path_dict:
data = urls.path_dict[path]()
return [data.encode()]
else:
return [views.other().encode()]
except KeyboardInterrupt:
return ['服务器已断开连接'.encode()] if __name__ == '__main__':
IP = '127.0.0.1'
PORT = 8088
server = simple_server.make_server(IP, PORT, run)
print('\033[31m服务器已建立,等待客户端连接中。。\033[0m')
server.serve_forever()

遇到的问题

第四版已经很好了,不过可能会频繁的使用到不同的html页面

模块优化

templates文件夹

为了避免文件类型的混乱 单独开设一个文件夹存储应用程序的 HTML 模板文件,这个文件夹就是templates

这些模板文件包含了应用程序的页面结构、布局和内容,使开发者能够更好地组织和维护页面。

static文件夹

static 文件夹通常用于存放静态资源文件,如 CSS 样式表、JavaScript 脚本文件、图像等。这些静态资源文件不会被您所使用的框架渲染,而是直接提供给浏览器以加载和显示页面。

通过将 HTML 模板文件放置在 templates 文件夹、静态资源文件放置在 static 文件夹,可以使框架应用更加清晰地组织和管理页面结构和静态资源,便于开发和维护。

手写web框架的更多相关文章

  1. Django框架——手写web框架、wsgiref模块、动静态网页、jinja2模块、主流web框架、Django简介、基本使用、app概念、目录结构、三板斧

    web应用 '''通过浏览器访问的应用程序!!!''' 1.两种模式c/s b/s B/S:browser---------------->server 2.web应用程序的有点 2.1 只需要 ...

  2. 手写web框架之加载Controller,初始化框架

    1,加载Controller     我们需要创建 一个ControllerHelper类,让它来处理下面的逻辑:      通过ClassHelper我们可以获取所有定义了Controller注解的 ...

  3. 手写web框架之实现依赖注入功能

    我们在Controller中定义了Service成员变量,然后在Controller的Action方法中调用Service成员变量的方法,那么如果实现Service的成员变量? 之前定义了@Injec ...

  4. 手写web框架之实现Bean容器

    实现Bean容器    使用ClassHelper可以获取所加载的类,但无法通过类来实例化对象,因此我们需要提供一个反射工具类,让它封装java反射相关的API,对外提供更好用的工具方法.将该类命名为 ...

  5. 手写web框架之加载配置项目

    一  定义框架配置项 在项目的src/main/resources目录下创建一个名为smart.propertiesd的文件,文件的内容如下: smart.framework.jdbc.driver= ...

  6. 手写web框架之开发一个类加载器

    ackage io.renren.common; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUti ...

  7. Django框架:1、手撸web框架、Django框架简介、安装与使用和小白必会三板斧

    Django框架 目录 Django框架 一.Django推导流程 1.纯手撸web框架 2.基于wsgire模块 3.代码封装优化 4.动静态网页 5.jinja2模块 6.前端.后端.数据库三者联 ...

  8. (二)springMvc原理和手写springMvc框架

    我们从两个方面了解springmvc执行原理,首先我们去熟悉springmvc执行的过程,然后知道原理后通过手写springmvc去深入了解代码中执行过程. (一)SpringMVC流程图 (二)Sp ...

  9. 手写SpringMVC 框架

    手写SpringMVC框架 细嗅蔷薇 心有猛虎 背景:Spring 想必大家都听说过,可能现在更多流行的是Spring Boot 和Spring Cloud 框架:但是SpringMVC 作为一款实现 ...

  10. 手写Spring框架,加深对Spring工作机制的理解!

    在我们的日常工作中,经常会用到Spring.Spring Boot.Spring Cloud.Struts.Mybatis.Hibernate等开源框架,有了这些框架的诞生,平时的开发工作量也是变得越 ...

随机推荐

  1. java -D的一些学习和使用

    背景 java开发的程序有很多进行配置的方式 可以通过 yaml文件或者是xml文件 也可以通过环境变量的方式. 1. 容器的话可以使用 -e 或者是env进行注入 2. K8S的话可以通过 conf ...

  2. elementUI封装 el-dialog

    讲解 // 讲解: @close="$emit('update:show1', false)"是子组件跟新父组件中的某值show1,将值变为false // :visible.sy ...

  3. 用户 'NT Service\SSISScaleOutMaster140' 登录失败

    用户 'NT Service\SSISScaleOutMaster140' 登录失败. 原因: 找不到与提供的名称匹配的登录名. 项目情况: 用户 'NT Service\SSISScaleOutMa ...

  4. STM32CubeMX教程27 SDIO - 读写SD卡

    1.准备材料 正点原子stm32f407探索者开发板V2.4 STM32CubeMX软件(Version 6.10.0) keil µVision5 IDE(MDK-Arm) ST-LINK/V2驱动 ...

  5. vs不同版本支持的c++版本和PlatformToolset,及在vs中切换c++版本

    找c++资料从网上找确实更快速,但要想深入地理解vc++建议看msdn文档. vs不同版本支持的c++版本 C++17: vs2017基本支持,vs2015部分支持. C++14: vs2017就可以 ...

  6. 每日一道面试题:Java中序列化与反序列化

    写在开头 哈喽大家好,在高铁上码字的感觉是真不爽啊,小桌板又拥挤,旁边的小朋友也比较的吵闹,影响思绪,但这丝毫不影响咱学习的劲头!哈哈哈,在这喧哗的车厢中,思考着这样的一个问题,Java中的对象是如何 ...

  7. Linux和Windows系统下安装深度学习框架所需支持:Anaconda、Paddlepaddle、Paddlenlp、pytorch,含GPU、CPU版本详细安装过程

    Linux和Windows系统下安装深度学习框架所需支持:Anaconda.Paddlepaddle.Paddlenlp.pytorch,含GPU.CPU版本详细安装过程 1.下载 Anaconda ...

  8. 强化学习基础篇[3]:DQN、Actor-Critic详细讲解

    强化学习基础篇[3]:DQN.Actor-Critic详细讲解 1.DQN详解 1.1 DQN网络概述及其创新点 在之前的内容中,我们讲解了Q-learning和Sarsa算法.在这两个算法中,需要用 ...

  9. 驱动开发:如何枚举所有SSDT表地址

    在前面的博文<驱动开发:Win10内核枚举SSDT表基址>中已经教大家如何寻找SSDT表基地址了,找到后我们可根据序号获取到指定SSDT函数的原始地址,而如果需要输出所有SSDT表信息,则 ...

  10. 顺颂秋冬<一>

    起名字真难. 原来想给这个合集起个积极的名字,记录鄙人浅薄的认知和内心的荒芜. 以及所遇见的温暖. 想来想去,不过是 浮生旧茶  西楼残月之类的 难堪大用. 后来想起来一句, 即,顺颂时祺,秋绥冬禧, ...