http协议与Nodejs中的http模块

1.概念

什么是http?
中文名:超文本传输协议
外文名:HTTP
工作层:应用层
基础:架构在TCP协议上
作用:规定WWW服务器与浏览器之间信息传递规范

http是一个简单的请求-响应协议,它通常运行在TCP之上。它指定了客户端可能发送给服务器什么样的消息以及得到什么样的响应。请求和响应消息的头以ASCII码形式给出;而消息内容则具有一个类似MIME的格式。这个简单模型是早期Web成功的有功之臣,因为它使得开发和部署是那么的直截了当。

2.发展背景

万维网WWW(world wide web)发源于欧洲日内瓦量子物理实验室CERN,正是WWW技术的出现使得因特网得以超乎想象的速度迅猛发展。这项基于TCP/IP的技术在短短的十年时间内迅速成为已经发展了几十年的Internet上的规模最大的信息系统,它的成功归结于它的简单、实用。在WWW的背后有一系列的协议和标准支持它完成如此宏大的工作,这就是Web协议族,其中就包括HTTP超文本传输协议。
在1990年,HTTP就成为WWW的支撑协议。当时由其创始人WWW之父蒂姆·贝纳斯·李(TimBerners—Lee)提出,随后WWW联盟(WWW Consortium)成立,组织了IETF(Internet Engineering Task Force)小组进一步完善和发布HTTP协议。
HTTP是应用层协议,同其他应用层协议一样,是为了实现某一类具体应用的协议,并由某一运行在用户空间的应用程序来实现其功能。HTTP是一种协议规范,这种规范记录在文档上,为真正通过HTTP协议进行通信的HTTP的实现程序。
HTTP协议是基于C/S架构进行通信的,而HTTP协议的服务器端实现程序有httpd、nginx等,其客户端的实现程序主要是Web浏览器,例如Firefox、InternetExplorer、Google chrome、Safari、Opera等,此外,客户端的命令行工具还有elink、curl等。Web服务是基于TCP的,因此为了能够随时响应客户端的请求,Web服务器需要监听在80/TCP端口。这客户端浏览器和Web服务器之间就可以通过HTTP协议进行通信了。

3.应用场景

HTTP诞生之初主要是应用于WEB端内容获取,那时候内容还不像现在这样丰富,排版也没那么精美,用户交互的场景几乎没有。对于这种简单的获取网页内容的场景,HTTP表现得还算不错。但随着互联网的发展和WEB2.0的诞生,更多的内容开始被展示(更多的图片文件),排版变得更精美(更多的CSS),更复杂的交互也被引入(更多的jS)。用户打开一个网站首页所加载的数据总量和请求的个数也在不断增加。
今天绝大部分的门户网站首页大小都会超过2M,请求数量可以多达100个。另一个广泛的应用是在移动互联网的客户端APP,不同性质的APP对HTTP的使用差异很大。对于电商类APP,加载首页的请求也可能多达10多个。对于微信这类IM,HTTP请求可能仅限于语音和图片文件的下载,请求出现的频率并不算高。

4.工作原理

HTTP是基于客户/服务器模式,且面向连接的。典型的HTTP事务处理有如下的过程:

  1. 客户与服务器建立连接;
  2. 客户向服务器提出请求;
  3. 服务器接受请求,并根据请求返回相应的文件作为应答;
  4. 客户与服务器关闭连接。

客户与服务器之间的HTTP连接是一种一次性连接,它限制每次连接只处理一个请求,当服务器返回本次请求的应答后便立即关闭连接,下次请求再重新建立连接。这种一次性连接主要考虑到WWW服务器面向的是Internet中成干上万个用户,且只能提供有限个连接,故服务器不会让一个连接处于等待状态,及时地释放连接可以大大提高服务器的执行效率。
HTTP是一种无状态协议,即服务器不保留与客户交易时的任何状态。这就大大减轻了服务器记忆负担,从而保持较快的响应速度。HTTP是一种面向对象的协议。允许传送任意类型的数据对象。它通过数据类型和长度来标识所传送的数据内容和大小,并允许对数据进行压缩传送。当用户在一个HTML文档中定义了一个超文本链后,浏览器将通过TCP/IP协议与指定的服务器建立连接。
从技术上讲是客户在一个特定的TCP端口(端口号一般为80)上打开一个套接字。如果服务器一直在这个周知的端口上倾听连接,则该连接便会建立起来。然后客户通过该连接发送一个包含请求方法的请求块。
HTTP规范定义了9种请求方法,每种请求方法规定了客户和服务器之间不同的信息交换方式,常用的请求方法是GET和POST。服务器将根据客户请求完成相应操作,并以应答块形式返回给客户,最后关闭连接。

5.运作方式

在WWW中,“客户”与“服务器”是一个相对的概念,只存在于一个特定的连接期间,即在某个连接中的客户在另一个连接中可能作为服务器。基于HTTP协议的客户/服务器模式的信息交换过程,它分四个过程:建立连接、发送请求信息、发送响应信息、关闭连接。
HTTP协议是基于请求/响应范式的。一个客户机与服务器建立连接后,发送一个请求给服务器,请求方式的格式为,统一资源标识符、协议版本号,后边是MIME信息包括请求修饰符、客户机信息和可能的内容。服务器接到请求后,给予相应的响应信息,其格式为一个状态行包括信息的协议版本号、一个成功或错误的代码,后边是MIME信息包括服务器信息、实体信息和可能的内容。

6.通信传输

连接过程
客户端输入URL回车,DNS解析域名得到服务器的IP地址,服务器在80端口监听客户端请求,端口通过TCP/IP协议(可以通过Socket实现)建立连接。HTTP属于TCP/IP模型中的运用层协议,所以通信的过程其实是对应数据的入栈和出栈。
报文
报文从运用层传送到运输层,运输层通过TCP三次握手和服务器建立连接,四次挥手释放连接。
TCP三次握手
为什么需要三次握手呢?为了防止已失效的连接请求报文段突然又传送到了服务端,因而产生错误。
比如:client发出的第一个连接请求报文段并没有丢失,而是在某个网络结点长时间的滞留了,以致延误到连接释放以后的某个时间才到达server。本来这是一个早已失效的报文段,但是server收到此失效的连接请求报文段后,就误认为是client再次发出的一个新的连接请求,于是就向client发出确认报文段,同意建立连接。假设不采用“三次握手”,那么只要server发出确认,新的连接就建立了,由于client并没有发出建立连接的请求,因此不会理睬server的确认,也不会向server发送数据,但server却以为新的运输连接已经建立,并一直等待client发来数据。所以没有采用“三次握手”,这种情况下server的很多资源就白白浪费掉了。
TCP四次挥手
为什么需要四次挥手呢?TCP是全双工模式,当client发出FIN报文段时,只是表示client已经没有数据要发送了,client告诉server,它的数据已经全部发送完毕了;但是,这个时候client还是可以接受来server的数据;当server返回ACK报文段时,表示它已经知道client没有数据发送了,但是server还是可以发送数据到client的;当server也发送了FIN报文段时,这个时候就表示server也没有数据要发送了,就会告诉client,我也没有数据要发送了,如果收到client确认报文段,之后彼此就会愉快的中断这次TCP连接。
驻留程序
其实简单说就是任何服务器除了包括HTML文件以外,还有一个HTTP驻留程序,用于响应用户请求。你的浏览器是HTTP客户,向服务器发送请求,当浏览器中输入了一个开始文件或点击了一个超级链接时,浏览器就向服务器发送了HTTP请求,此请求被送往由IP地址指定的URL。驻留程序接收到请求,在进行必要的操作后回送所要求的文件。在这一过程中,在网络上发送和接收的数据已经被分成一个或多个数据包(packet),每个数据包包括:要传送的数据;控制信息,即告诉网络怎样处理数据包。TCP/IP决定了每个数据包的格式。如果事先不告诉你,你可能不会知道信息被分成用于传输和再重新组合起来的许多小块。
许多HTTP通讯是由一个用户代理初始化的并且包括一个申请在源服务器上资源的请求。最简单的情况可能是在用户代理(UA)和源服务器(O)之间通过一个单独的连接来完成。
当一个或多个中介出现在请求/响应链中时,情况就变得复杂一些。中介有三种:代理(Proxy)、网关(Gateway)和通道(Tunnel)。一个代理根据URI的绝对格式来接受请求,重写全部或部分消息,通过URI的标识把已格式化过的请求发送到服务器。网关是一个接收代理,作为一些其它服务器的上层,并且如果必须的话,可以把请求翻译给下层的服务器协议。一个通道作为不改变消息的两个连接之间的中继点。当通讯需要通过一个中介(例如:防火墙等)或者是中介不能识别消息的内容时,通道经常被使用。

7.nodejs中的服务器端知识

7.1 服务器端概念

  • 网站的组成:
  1. 客户端:用户界面,浏览器,运行着使用html、css、js编写的网站
  2. 服务端(服务器的压力远比客户端高,所以一般对服务器电脑的配置要求很高):接收请求,做出响应,处理业务逻辑和存储数据
  • IP:是互联网中设备的唯一标识
  • 域名:就是IP地址的别名,为了方便我们记忆
  • 端口:可以理解成银行的柜台窗口编号,是我们服务器向外提供服务的口子,范围是0~65536,我们应用程序一般从3000起步
  • URL:统一资源定位符,是标识互联网中的资源地址的编址方式
  • 一个完整的URL包含:传输协议://IP或域名:端口/资源路径
  • 一般网站应用的默认端口是:80,可以省略不写
  • HTTP(Hyper Text Transfer Protocol):超文本传输协议,超文本就是用HTML写的文本
  • 本机IP:127.0.0.1
  • 本机域名:localhost

7.2 创建网站服务器

// http 模块为内置模块不需要安装
let http = require("http");
//url模块提供了用于url分辨和解析的实用程序。
const urlLib = require('url');
// 创建server服务器对象
let server = http.createServer();
//监听对当前服务器对象的请求
server.on('request', function (req,res) {
    //method为解析器支持的HTTP方法列表。
    if (req.method === 'GET') {
        /*parse()方法解析一个JSON字符串,
        构造由该字符串描述的JavaScript值或对象。
        可以提供一个可选的恢复器函数,
        以便在返回结果对象之前对其执行转换*/
        var urlObj = urlLib.parse(req.url, true);
        console.log(urlObj);
        if (urlObj.pathname == "/getIpMsg") {
        // 此处添加相应的函数模块
        }
    }
});
// 服务器监听的端口号
server.listen(3000, function () {
    // 启动监听端口号成功时触发
    console.log("服务器启动成功!")
});

补充说明:node也是有基于事件驱动特性的。

7.3 http协议

  • HTTP:超文本传输协议,它基于客户端和服务端架构工作,是请求和响应的标准
  • 报文:是HTTP请求和响应过程中传递的数据,分为请求报文(请求头)和响应报文(响应头),它遵守规定好的格式
  • 请求方法:
  1. GET:用来告诉服务端,我这次请求主要目的是获取数据
  2. POST:用来告诉服务端,我这次请求主要目的是添加数据
  • 在服务端中如何获取客户端的请求方法?:req.method
  • form表单的两个重要属性(由于有默认跳转行为,用户体验较差,所以我们一般不用这个提交数据,等后面学习了ajax之后,可以在背后偷偷摸摸发送数据):
  1. method: 指定请求方法
  2. action:指定请求地址
  • 获取请求地址中的资源路径:req.url(注意:这里获取的仅仅是资源路径,并不是完整的URL)
  1. 注意:请求时,如果没有带资源路径,如发送的是这个请求地址:http://localhost:3000,这时req.url获取到的是/
  2. 获取请求报文:req.headers,就是一个对象,可以通过键值对的点语法或者中括号语法获取到键的值
  • HTTP状态码(仅仅只是一个标识,是我们人为约定好的,浏览器内部也是遵守这种逻辑,并不能影响响应数据,只是用来告诉客户端对于本次请求,对应的响应状态):
    • 200:请求成功
    • 500:服务端错误
    • 400:客户端错误
    • 404:资源没有找到

  • 设置HTTP状态码:res.writeHead(500)
    • 响应内容类型(为了告诉浏览器,本次请求响应给你的数据格式,浏览器会根据这种格式去解析数据):
    • text/plain:纯文本,默认
    • text/html
    • application/javascript
    • application/json
    • image/jpeg
    • …

  • 设置响应内容类型以及编码格式:res.writeHead(200, { ‘Content-Type’: ‘text/html;charset=utf8’ })

补充说明(重点理解):服务端的程序是我们自己写的,客户端(浏览器)的程序是浏览器厂商的程序员写的(会自动读取服务端响应给客户端的信息,也就是响应头中的信息)。

7.3.1 get请求参数

  • 传递参数的两种方式:get、post
  • get参数放在请求地址中,形如:http://localhost:3000/index?name=zs&age=18
  • 借助系统模块url把req.url解析成对象:url.parse(req.url, true)
    • 第一个参数是字符串形式的url
    • 第二个参数是指是否将查询参数转换成对象,默认false
  • 获取查询参数和资源路径:const { query, pathname } = url.parse(req.url, true)

7.3.2 post请求参数

  • post请求参数是放在请求报文中
  • post参数理论上来讲是可以有无限多个的,所以服务器不是一次性接收的,防止卡顿,接收时需要使用data和end事件
    • data事件:监听每一次的请求数据,当数据量过大时,会执行多次
    • end事件:监听请求参数传递结束,当数据传递完成就会触发,只会执行一次
  • post参数默认的格式(x-www-form-urlencoded)实际上和get参数的格式是一样的,在浏览器控制台中看到的是对象是因为浏览器为了方便我们查看给我美化了
  • 可以使用系统模块querystring把请求参数转换成对象

7.3.4 范例

const querystring = require('querystring')
app.on('request', (req, res) => {
    let data = ''
    req.on('data', (dataChunk/* 本次获取到的数据块,并不是一次性拿到的 */) => {
        data += dataChunk
    })
    req.on('end', () => {
        console.log(data) // name=zs&age=18
        const params = querystring.parse(data) // { name: ‘zs’, age: ‘18’ }
        res.end('ok, receive successfull.')
    })
})

7.4 路由

服务端逻辑,由服务端决定,实际上就是服务端定义的资源路径列表,定义了各个路由对应的资源。

7.4.1 静态资源

就是可以直接响应给客户端的资源,一般不会有变化,比如:html/js/css/image,同一个路由,多次访问不会有变化。
• 处理默认请求地址/:if (pathname === ‘/’) { pahtname = ‘/default.html’ }
• 注意:浏览器在解析html代码时,如果遇到外链资源(js/css/image),如:link、img、script标签,浏览器就会自动发送请求获取该资源,这时每个资源的类型都不一样,怎么保证响应内容类型是匹配的呢?就不能写死text/html了,需要借助第三方模块mime的getType(filepath)方法动态获取资源类型,通过:npm i mime安装,通过:const mime = require(‘mime’)导入
• 补充说明:为什么不设置,有些浏览器也能认识该资源?是因为这个浏览器内核比较高级,如果到lowb浏览器中访问就凉了,这都是网站的问题,我们让代码更健壮就需要解决这种隐患

7.4.2 动态资源

同样的请求地址,响应不同的资源,比如:http://localhost:3000/center?userId=1、http://localhost:3000/center?userId=2,同样的资源路径,响应的页面不同。

7.5 同步、异步API的概念

同步API:从上往下执行,当前代码执行完后,才会继续往下执行,范例:

console.log(1) 
console.log(2) 
// 1 
// 2

异步API:当前代码的执行不会阻塞后续代码的执行。范例:

	console.log(1)
	setTimeout(() => {
		console.log(2)
	}, 1000)
	console.log(3)
	// 1
	// 3
	// 等待1秒后
	// 2

参考文章
HTTP和HTTPS协议
nodejs中的服务器端知识

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值