应用层协议之HTTP协议

一.HTTP协议报文格式

HTTP协议包括了请求和响应两个,所以要分两部分看待。如何查看到HTTP协议的报文格式?用抓包工具。我们用Fiddler即可,它是专用于抓HTTP包的一个工具。

Fiddler 相当于一个 " 代理 ".
浏览器访问 sogou.com , 就会把 HTTP 请求先发给 Fiddler, Fiddler 再把请求转发给 sogou 的服务器 .
sogou 服务器返回数据时 , Fiddler 拿到返回数据 , 再把数据交给浏览器 .
因此 Fiddler 对于浏览器和 sogou 服务器之间交互的数据细节 , 都是非常清楚的 .

1.请求的格式

首行:

首行就是报文的第一行,有三个部分,每个部分用空格分割。

第一部分->方法:  表示HTTP请求的方法,上面这个请求的方法是GET

第二部分->URL:叫做唯一资源定位符,描述了要访问的资源在网络上的位置

第三部分->版本号:这里是HTTP/1.1,表示这里的HTTP用到的是1.1这个版本的

什么是URL?

它描述了某资源在网络上所处的位置,例如https://www.baidu.com。。格式如下:

1.协议方案名:http://或https://

2.登录(认证)信息:login:password。这是可选项,若非需求,可以不填。现在几乎不用了

3.@分割符

4.服务器地址:IP或域名

5.服务器端口号:一个主机可能有很多端口号。假设这一项没有写,那么就会默认分配一个端口号。对于http请求,默认访问80;对于https请求,默认访问443.

6.带层次的文件路径:描述了要访问服务器的哪一个资源(一个服务器提供的资源很多)。这个写法虽然很像目录,但是实际上不一定是以目录形式存储资源,可能数据是在硬盘数据,也可能是内存数据,还有可能是通过网络访问其他服务器拿到的数据,还有可能是菜谱计算出来的数据。这里的目录结构怎么写,也和服务器代码有关。

7.查询字符串(query string):这是键值对的数据结构。键与值之间用等号分割,对与对之间用&分割。query string的对是程序员自己定义的,不像header中是标准规定的

8.#:片段标识符。有些网页内容较长,就可以分成多个片段,通过片段标识符,就可以完成页面内部的跳转。通过不同的页面标识来跳转到文档的不同章节

我们来举个例子:假设我改行做厨师,在一食堂17号窗口卖鸡蛋灌饼,有一个客户想要买官兵,那就可以将http协议写成:http://海大一餐厅:17/煎饼/熏肉煎饼?葱=不要&辣椒=微辣

对于query string:若value部分要包含一些特殊符号,往往需要进行urlencode操作。

例如:搜索c++,出现了?query=C%2B%2B。这是为什么?因为像+?:/等这些符号在url中已经有了特殊的用途,所以如果在value中也有这些符号,就可能使浏览器/http服务器对url的解析出现问题。

urlencode本质上是一种转义字符。+的ASCII码值就是2B,而%标识这是转义的结果。

中文也需要转义,可以用urlencode在线工具,比如你好,就是转义成%E4%BD%AO%E5%A5%BD。其中E4BDA0就是utf8编码中的你,E5A5BD就是utf8中的好,urlencode就是在utf8的基础上在每个字节前面加上了注意字符%

所以后面使用url一定要记得进行urlencode工作,若不处理,可能会是请求无法征程进行

认识方法:

主要包括这几个,其中最重要的是GET和POST。GET表示获取,POST表示请求(常用于登录以及上传文件时)。

post请求通常会把将要传给服务器的请求数据放到最下面的body部分,然而get请求一般会把请求内容放到url的querystring中。但这只是建议,不是硬性要求。

其实这些请求,初心是为了表示不同的语义,get获取,post上传,delete删除……但是在实际使用中,这个初心已经被遗忘了,所以在实际使用中,程序员如果使用就更随意了,可以用get上传文件,也可以用post获取资源,同时任何使用post的场景也都可以用put代替……

面试题:谈谈GET和POST的区别

本质上,get和post没有区别

虽没有本质区别,但在使用习惯上,也有区别:

1.get经常把要传输的请求放到query string中,post经常放到body中。但并非绝对,get也可以把请求放到body中……(前提是客户端和服务器都是按照同样的方式进行处理,所以还是建议遵守约定)。

2.语义上,get大多用来获取数据,post大多用来传输数据。

注意分辨下面的这些关于get和post的说法

1.get请求能够传输的数据量有上限,而post无。这是错误的!!这个说法是基于一个历史遗留问题:早期版本的浏览器硬件资源匮乏,所以针对get请求的url长度做了限制。但实际上,RFC标准文档中没有规定url能有多长,而且目前浏览器和服务器在实现过程中,url可以很长(甚至是使用url来传图片)

2.get请求传递数据不安全,post请求传递数据更安全。这个说法也是错的!!!它这个说法的依据是:若使用get请求实现登录,在点击登陆时,就会把用户名和密码放到url中,进一步显示到浏览器的地址栏中,这不就被别人看到了吗?而post请求时在body中,不会再界面上显示。这其实是错误的看法。我们所说的安全,指的是数据不容易被黑客获取到,或者说被获取到后不容易破解。但实际上上面说的url显示和body显示对黑客来说都一样。实际上这个密码一抓包就能够被拿到,但这个密码是加密的。所以此处的安全性和是否在body中无关,而关键在于是否加密。

3.get只能给服务器传输文本数据,而post可以给服务器传输二进制数据。这个说法也是错的!!!首先,若使用body存放数据,get可以直接存放二进制数据;若使用url,可以通过base64把二进制进行转码,再放到url的query string中

4.get请求是幂等的,post请求是非幂等的。这个说法不够准去,但也不是完全错误。幂等指的是:输入相同的数据,输出是稳定的。get和post是否幂等,取决于代码的实现。个体是否幂等也不是绝对的。一个典型的不幂等例子:搜狗的广告搜索(广告数据是通过发送get请求获取的,但由于广告的更新,每次得到的响应是不一样的)

5.get请求可被浏览器缓存,post请求不可以。这也是不够准确的,幂等就对应可以进入缓存,非幂等对应不可以进入缓存。

什么是浏览器缓存?有时候我们进行抓包操作时会发现没有抓到包,这就是命中率浏览器缓存。浏览器上显示的页面其实是从服务器这边下载的html。html内容可能很多,通过网络加载消耗的时间会很长。所以浏览器一般会自带一个缓存,把之前加载过的页面,保存到本地硬盘上,下次直接读取硬盘即可。

6.get请求可被浏览器收藏夹收藏,post不能,因为收藏时可能会把body丢了。这个说法就暂时倾向于对。但是不是核心区别。

请求“报头”(header):

是从首行的下一行到最后的结束标志。它是键值对的数据结构(都是标准规定的),每对独占一行。键与值之间用冒号和空格分割(注意是和不是或)。

空行:

请求头的结束标志

正文:

在空行的下面,有的请求有,有的请求没有

2.响应的格式

首行:

第一部分:版本号

第二部分:状态码(比如上面的200)

第三部分:状态码描述(比如上面的OK)

响应头(header):

也是多个键值对,同上,到空行结束

空行:

用来标记响应头的结束

正文:

在空行的下方,可能较长,可能有很多种格式:HTML/CSS/视频/图片/JSON……。上面这个响应的body部分我们没有看懂,这是因为有些body太长,所以fiddler在抓包时进行了压缩,我们可以点击fiddler上面的一行字符串进行还原,就是点下面这个黄色的栏

3.认识header

下面介绍一些常见的键值对

1.host:

表示主机的地址和端口号/或使用域名。它在url中也存在,但不一定完全相同

2.content-length:描述body中数据的长度,content-type:描述body中数据的格式。

只有当请求中有body,才会有这两个属性。

TCP涉及到粘包问题。http在传输层是基于TCP的。使用同一个TCP协议传输多个http数据包,此时就会使多个http数据包在tcp接收缓冲区中挨在一起。接收方解析时,就需要清除http数据包的边界。对于get这种一般没有body的请求,直接使用空行;对于post这种有body的,就要结合空行和content-length来明确边界(空行是header的结束,同时是数据请求的开始;content-length就是标志着数据的结尾)

body中的数据格式可选择的有很多:

在请求中:json,from表单格式,form-data格式……

在响应中:html,css,js,json,图片……

json常在登陆时看到

form表单格式就相当于把GET的query string放到了body中。上传文件时常常是form-data格式。如下是刷新一个网页后抓到的包:

蓝色的一般是,紫色的是CSS,绿色的是js,黑色解压缩是json/image/png图片。

简单提一嘴,html。css,js都是构成网页的主体。html表示页面的骨架(页面上有啥东西),css是页面的样式(页面长啥样),js表示页面的行为

3.User-Agent(UA)

表示浏览器/操作系统的属性

比如上面这个。Windows NT 10.0; Win64; x64描述了操作系统的属性,后面描述了浏览器的信息

4.Referer

表示当前页面是从哪个页面跳转过来的。

如果直接在地址栏里面输入url或者点击收藏夹,一般是没有referer的。

我们知道每次搜索一些东西时,就会出现一些广告,那么广告主怎么知道这些请求时来自百度还是搜狗?就是通过referer来区分。但是也有可能有人从中作祟把referer给改了,可能本来是搜狗的referer,改成了别的平台的referer(这也是运营商劫持。哪运营商有能力劫持吗?有,用户数据时通过运营商的设备路由器交换机啥的进行转发的,在路由器上部署一些特定的程序就能很轻易获取到数据,也很容易修改。那运营商有动机进行修改吗?有,运营商也有自己的广告平台,它可和特定的广澳平台合作……)。为了解决这样问题,百度,搜狗等在技术上对此进行了反制:使用https。http是明文传输,https是密文传输

5.cookie

浏览器在本地存储数据的一种机制

浏览器发送了获取页面的请求,服务器就会返回页面进行响应。浏览器的数据来自于服务器,浏览器的后续操作也要提交给服务器。所以服务器这边管理类一个网站的各种核心数据。

但是在程序运行过程中,也可能会有一些数据,需要在浏览器这里储存,并在后续的请求时,数据可能要再次发送给服务器(比如:上次登录时间,上次访问时间,用户信息,累计访问次数……)向这些临时性数据,存储在浏览器中就比较合适。

本地存储,更易想到的是直接存放到本地文件中。但实际上,浏览器为了安全性,进制网页直接访问你的电脑的文件系统,所以网页代码也就无法生成一个阴盘文件来存放数据了。(害怕有一个网站有病毒,把硬盘上的关键文件给删了)。

为了保证安全性,又能够存储,所以引入了cookie。它也是按照硬盘文件的方式来保存,但是浏览器把操作文件给封装了,网页只能给cookie中存放键值对(简单的字符串)

cookie往往是从服务器返回的数据(也可能是页面自己生成的)

cookie存储到浏览器所在主机的硬盘中,并按照域名位维度来存放(每个域名下可存放自己的cookie,不冲突)

后续再请求服务器是,就会把cookie中的内容自动带入到请求中,发给服务器,服务器通过cookie做一些逻辑处理。

cookie中的键值对都是程序员你自定义的

4.认识响应的“状态码”

状态码表示访问一个页面的结果(是成功还是失败,还是一些其他情况)。一下是一些常见的状态码:

以2开头的

都表示成功。200表示ok

以3开头的

表示重定向。指的是请求中访问的是A这样的地址,响应返回了一个重定向报文,告诉你要去访问B的地址。(就好像我去问老师题,老师正好没有时间,所以就让我去问同学)。

当发生页面跳转/某个网站服务器迁移了,就可能给一个重定向响应。

301是永久重定向,可入缓存

302是临时重定向。在登陆页面中经常会见到 302. 用于实现登陆成功后自动跳转到主页.

重定向响应报文中,会在header中搭配一个location,记录将要跳转到的页面

以4开头的

表示请求错误,请求可能不符合服务器要求

404:NOT FOUND,表示请i去访问的资源在服务器中不存在

403:Forbidden,表示访问的资源没有权限。有的页面通常需要用户具有一定的权限才能访问(登陆后才能访问). 如果用户没有登陆 直接访问, 就容易见到 403

405:Method Not Allowed,就是说对方不一定支持我们所用的方法(get/post……)

418:I am a Teapot,这是一个特殊的状态码,418是HTTP RFC文档中专门规定的状态码,没有实际意义,只是开个玩笑,叫“彩蛋”

以5开头的

一般是服务器挂了。

500:后面咱们自己写服务器代码时,容易写出500(代码有bug)

504:Gateway TimeOut。当服务器负载很大时,它处理单条请求的时间就会很长,就可能导致出现超时的情况

讲到这里,我们来复习一下,哪些地方要用到键值对:1.query string 2.header 3.cookie 4.body 中的form表单格式,以及json格式

小结一下状态码:

1xx:  hold on,表示接收到请求正在处理

2xx:  here you go,表示请求成功处理完毕

3xx:  go away,需要进行附加操作以完成请求,重定向

4xx:  you fucked up,客户端错误,服务器这边无法处理请求

5xx:  i fucked up,服务器出错

二.通过form表单构造http请求

form是html中的一个常用的标签

html表单用于收集用户输入的信息

HTML 表单表示文档中的一个区域,此区域包含交互控件,将用户收集到的信息发送到 Web 服务器。

HTML 表单通常包含各种输入字段、复选框、单选按钮、下拉列表等元素。

1.form发送get/post请求

html中包和案例很多标签,这些标签都是成对出现的,包括了开始标签和结束标签,两标签之间就是标签内容。同时点击!和tab键,就可以自动生成一个html的基本代码模板:

其中head中放的是一些属性,body中放的是页面显示的内容。html中有哪些标签,都是啥内容,含义是啥,都是由标准规定的。

form标签的重要参数

<form> 元素用于创建表单,编写html表单用到了form标签,在form的开始标签中可以写属性,可以有多个属性,每个键值对之间用空格分开,键和值之间用等号,键不需要有引号,值需要引号。如下:

如上,其中action表示要访问的请求的url路径是什么(也可以加一个IP端口号);method描述了当前构造的是什么请求。注意:form表单只支持get和post请求,不支持其他http方法

input标签

光有form标签还不够,还要有input标签,input> 元素是最常用的表单元素之一,它可以创建文本输入框、密码框、单选按钮、复选框等。如下:

type 属性定义了输入框的类型,其中text表示这是一个文本输入框,name属性表示将向服务器发送一个键名为name的键值对,键值对的值就是用户即将输入的内容。也就是说name属性表示构造出的表单的query string中的key,query string中的value就是用户输入到内容

若type是submit就代表这是个提交按钮,value: input 标签的值. 对于 type submit 类型来说, value 就对应了按钮上显示的文本.

如上就是我们自己创建出来的一个html,然后可以在上面输入值

点击提交后,用fiddler抓包发现是404错误码,这是因为我们访问的abc.html是不存在滴。

打开记事本看一下,这就是刚才构建的一个get请求,你看,首行的query string就是我们的输入框的名字和用户输入到信息

三.通过ajax方式发送请求

form表单方式发送请求有缺陷,它只能发送post和get请求。

ajax通过js提供的api来构造http请求,针对拿到的响应,同样可用js进行显式处理

浏览器原生提供了ajax的api,但是很难使用,不过还有第三方库封装了ajax,我们就用jquery这个库

1.引入jquery库

在浏览器上搜索jquery cdn,找到min.js版本,复制其连接,粘贴到script标签的src属性:

然后就可以在script标签之间编写代码了

2.编写代码

如上,$是一个jquery中定义的全局变量名,一般用$来调用jquery中的一些方法。

ajax方法的参数是一个js对象。javascript中的对象与java中的对象不一样。js中的对象是用一对大括号组织起来,其中是一些键值对来描述属性名和值。我们继续编写:

这里,type表示发送的请求的类型,url表示向谁发送请求,success里面有一个函数,这个函数不是立即执行,而是在服务器返回200这样的响应后,才会执行success,也称为回调函数。里面的形参body就是返回的响应中的body,console.log(body)表示打印body的内容。

下面是发送post请求的代码:

let是在定义变量,这里的body就是一个js对象,在ajax中data就是正文部分,JSON.stringify(body)表示把body这个js对象转成字符串。

注意:url一定要写在body之前。

四.Https

HTTPS也是一个应用层协议,是在HTTP协议的基础上引入了加密

1.啥是加密

加密就是把明文(要传输的信息)进行一系列变换,生成密文;解密就是把密文转化成明文

在加密和解密过程中,需要一个或多个中间数据辅助进行这个过程,这些数据就叫做密钥。

密码学中,加密就有两种方式:对称加密和非对称加密

2.https的工作过程

https就是要保证数据安全,所以目的就是针对header和body进行加密

引入对称加密

对称加密就是使用同一个密钥进行加密解密

首先,客户端使用密钥进行对称加密,然后发送给服务器,服务器就又使用同一个密钥进行解密,即使在数据传递期间,黑客截获了请求,由于他没有密钥,所以无法对内容进行解密。

但是有个问题,服务器是为多个客户端提供服务的,会与多个客户端同时进行通信,所以客户端使用的密钥是不同的,这样才能保证数据安全性。这就需要客户端在与服务器建立连接的过程中通过网络将自己的密钥进行传输。

但要是在传输密钥的过程中被黑客截取到,不也凉了?这加密就形同虚设

那么如何让密钥更加安全的到达服务器?那就要对密钥加密~~是否搞个密钥2对密钥1加密?这就成了循环问题,最终都被黑客拿到了。如何解决?非对称加密

引入非对称加密

非对称就是加密和解密使用的不是同一个钥匙

这里涉及到公钥和私钥。公钥加密私钥解密或者私钥加密公钥解密

过程就是:服务器生成一对公钥和私钥,服务器把公钥返回给客户端,把私钥自己保存好。客户端仍然生成一个对称钥,用服务器的公钥对对称钥进行加密,然后将加密后的对称钥返回给服务器。这是要是黑客截获到了对称钥,他也是无能为力的,因为他没有服务器手里的私钥,不能进行解密,所以就拿不到对称密钥。然而服务器手里有私钥,他就可以对加密后的对称密钥进行解密,接下来客户端与服务器就可以使用这个对称密钥进行加密解密了。

理论上,黑客拿到加密后的对称密钥,可能推算出来私钥是啥,但是计算量超大,即使是最牛超算,也得算好多年。

既然有了非对称加密,那为啥还要使用对称密钥?因为非对称的成本太高了,但运算速度低。所以只是使用非对称加密进行关键环节(传递密钥,一次性工作,体积不大),后续传输过程就使用效率高的对称加密。

中间人攻击

其实上述过程还有一个严重的漏洞,黑客利用好此漏洞,就也可以获得明文。我们来重新模拟一下传递过程:

客户端发送请求询问公钥,服务器将提前生成的公钥pub1放到响应中返回,同时自己存放好私钥pri1;

响应返回过程中,黑客截取到,黑客自己也生成一对公钥私钥pub2  pri2,并将截获的响应中的pub1替换成pub2并返回给客户端。

客户端就拿着pub2对生成的对称密钥进行加密,并返回给服务器。

对称密钥返回过程中,黑客用自己的pri2进行解密,拿到了对称密钥,然后又拿pub1对对称密钥进行加密,返回给服务器(为了不让服务器发现端倪)。

接下来,客户端与服务器之间的所有数据就被黑客截获了。

这又要如何解决?之所以能进行中间人攻击,就是因为客户端没有分辨能力,不知道这个公钥是伪造的。这里的分辨不能进行自证,所以引入了第三方“公证机构”

引入证书

网站开发人员搭建服务器时就立马生成了公钥和私钥(只有这一份就好,不必每个哭护短都有一对不同的),要想成功搭建一个网站,就要向公证机构提出申请(提交一些材料,包括域名,厂商,公钥……),机构公证对材料进行审核,审核通过就会给服务器颁发证书(这里的证书不是纸质的,而是一段结构化数据,里面包含了很多重要信息,如:网站域名,服务器公钥,证书的过期时间,数字签名……)。在谷歌浏览器的右上角有三点,点击,找到设置,搜索管理证书,就可以看到谷歌的证书

在客户端和服务器刚一建立连接时,服务器就会返回一个证书,客户端拿到证书后,就会对证书进行校验,这个校验就是拿出公钥,验证公钥是否被修改了。

证书的校验——核心机制“数字签名”

数字签名其实就是被加密的校验和

颁发证书时,公证机构会对证书中的各个属性计算出一个校验和,并对校验和进行加密,就得到了数字签名。(这里的加密也是非对称加密。公证机构自己生成了一对与服务器不同的公钥私钥,公证机构自己持有私钥,公钥就发给各个客户端设备(往往公钥是内置到系统中的,安装操作系统时,就会自带公证机构的公钥))。

客户端拿到数字签名后,就会用系统内置的公钥对其进行解密,得到校验和。然后客户端再重新计算一遍校验和,看看与解出来的一不一样,就知道是否被修改了。

上述机制下,黑客就无法对证书内容进行修改了。他要想将证书中的公钥替换成自己的,客户端就根据计算结果与校验和的不同看出来。

那么黑客能否自己计算一个数字签名?不能!!!校验和好酸,但是对校验和机型加密,得用到公证机构的私钥才行,要不然客户解不了密

那黑客能否自己申请一个证书,替换服务器证书?行不通。申请证书就需要提供一系列资料,其中就有网站域名,认证机构会看你这个域名是不是你所拥有的

总结

https一共涉及到三对密钥:

第一对——对称密钥:用于客户端和服务器后续传输数据

第二对——非对称密钥:辅助对称密钥的传输过程

第三对——非对称密钥:对计算出来的校验和进行加密

这一套流程是由SSL这样的协议规定的(后来改名为TLS)。这个加密不仅用于https,也用于其他场景,比如JDBC编程中,setUrl:

jdbc:mysql://127.0.0.1:3306/java111?characterEncoding=utf8&useSSL=false;

其中useSSL=false;就表示关闭加密,客户端与服务器之间进行明文传输

五.Tomcat

我们知道http协议就是http服务器和http客户端之间交互数据的格式

Tomcat是用java写的http服务器。浏览器,Postman,爬虫程序:是http客户端。

我们也可以用java Socket api来实现http服务器,但是有些大佬已经写好了http服务器,我们只需要调用api构造业务逻辑即可。Tomcat就是Java中最流行的http服务器。

1.下载tomcat

在必应搜索Tomcat,找到ApacheTomcat,直接解压缩就可以得到一个目录,这个目录就可以直接使用了。(Tomcat是一个绿色软件,无需安装,解压缩后就能使用,但前提是电脑上必须要有JDK)。

点开这个解压缩后的目录:

bin目录下放的是tomcat相关可执行脚本(.bat是windows上的批处理程序,.sh是Linux上的批处理程序,两者的工作效果是一样的)其中,启动tomcat就用到里面的startup.bat/sh,最终,tomcat就是个控制台程序,没有界面。

看到这个信息,就是启动成功。

里面是乱码,是因为tomcat默认使用utf8编码,而windows的控制台cmd使用的是GBK。

在浏览器中输入127.0.0.1:8080就可以看到tomcat的欢迎页面:

conf目录:放置的是tomcat的配置文件。一个程序的功能非常丰富,需要按需开启功能。tomcat的配置主要是通过xml的方式来提供

lib目录:放到是运行过程中依赖的jar包

logs目录:放的是日志(调试服务器的最重要手段)里面的内容就hi是控制台上的内容

webapps目录:里面放了若干个webapp(其实就是常说的网站)(包含了一个网站的后端代码和前端代码)。在里面,以后还会有war包,就是一个压缩包文件(这是使用tomcat发布程序时的方式。写好的一个网站,可以打包成一个war包,拷贝到tomcat的webapp中,tomcat就会自动对war包进行解压缩,从而完成网站的部署和加载)

2.尝试部署静态页面

在webapps里面创建一个新目录hello,再在这个目录下创建一个hello.html,用vscode打开,如下编辑:

也就是在body标签中写一句hello Java 110

然后重启tomcat,在浏览器搜索127.0.0.1:8080/hello/hello.html,就可以看到:

这就显示了tomcat的作用:可以让浏览器通过网络来访问html页面。

其实,直接在文件夹中点击hello.html也能打开这个页面,但不同的是,这是让浏览器打开一个本地文件,而不是通过网络访问,而且tomcat的方式还可以访问别人电脑的页面,但本地文件的方式只能访问自己电脑的页面。

这只是简单的静态页面,以后我们还可以根据代码来部署动态页面(就是会随时间改变而变化,或与用户相关……)

相关推荐

最近更新

  1. TCP协议是安全的吗?

    2024-04-02 03:46:02       18 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-04-02 03:46:02       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-04-02 03:46:02       18 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-04-02 03:46:02       20 阅读

热门阅读

  1. Linux命令基础

    2024-04-02 03:46:02       15 阅读
  2. 题解:CF1934A(Too Min Too Max)

    2024-04-02 03:46:02       22 阅读
  3. 【代码随想录】【动态规划】day39:不同路径

    2024-04-02 03:46:02       16 阅读
  4. EMF相关学习文档

    2024-04-02 03:46:02       15 阅读
  5. web服务应用术语

    2024-04-02 03:46:02       17 阅读
  6. 阿里巴巴实习面经

    2024-04-02 03:46:02       21 阅读
  7. 竞赛常考的知识点大总结(二)基础算法

    2024-04-02 03:46:02       21 阅读
  8. vue3中computed详解

    2024-04-02 03:46:02       16 阅读
  9. vue——computed和methods的区别

    2024-04-02 03:46:02       15 阅读
  10. Vue 使用 array.flatMap()例子

    2024-04-02 03:46:02       15 阅读
  11. 远程过程调用-buttonrpc源码解析6-函数调用

    2024-04-02 03:46:02       16 阅读