超文本传输协议(HTTP,HyperText Transfer Protocol)是互联网上应用最为广泛的一种网络协议
- 接收请求
- 处理请求
- 发送响应
net 为什么不能处理浏览器的响应呢?
http 模块和 net 模块之间的区别
http 模块的简单使用
(1). 创建服务器,得到一个 Server 实例对象
- 任何请求都会触发该 request 请求事件,然后执行事件处理函数
- 也就是说所有的请求入口就是这个 request 事件
- 如何区分不同的请求
- 每个请求有请求报文: 请求头、请求路径、请求方法等信息
- Node 将每一个请求中的请求报文信息解析为一个对象:Request ,挂载给请求处理函数的第一个参数
- 也就是说可以通过 Request 请求对象拿到一些请求报文信息,例如请求方法、请求路径、请求头部字段等信息
- 同时,Node 还提供了一个接口对象:Response
- 该对象可以用来给当前请求发送响应数据
(2). 监听服务器 Server 对象的 Request 请求事件,设置请求处理函数
(3). 绑定监听端口,启动服务器,设置启动成功之后的回调处理函数
|
|
对不同的请求发送不同的响应
- 当用户访问
'/'
的时候,返回 index page - 当用户访问
'/add'
的时候,返回 add page - 当用户访问
'/about'
的时候,返回 about page - 当用户访问
'/xxx'
的时候,返回 404
(1). 获取当前的请求路径(通过 Request 请求对象的 url 属性获取)
这里的请求路径永远都是以 /
开头的
例如你在浏览器地址中输入的是:
http://127.0.0.1:3000
则 url 就是 /http://127.0.0.1:3000/
则 url 就是 /http://127.0.0.1:3000/add
则 url 就是 /add
(2). 发送响应
2.1 请求之后,可以使用 res.write 方法发送响应
2.2 注意:res.write 可以向响应流中多次发送数据,
- 但是一定要在写完响应流数据之后调用
res.end()
方法结束响应。 - 否则客户端浏览器还认为你的数据没有发送完毕,一直等待接收。
2.3 一般发送响应数据的时候,很少有这种需要多次调用 write 方法来发送的数据
- 就是说一般就是
res.write('响应数据')
,res.end()
结束响应 - 所以,可以使用
res.end('响应数据')
直接发送响应数据,同时结束响应
|
|
根据不同请求响应不同内容
因此,可以这样来判断
|
|
处理页面中的静态资源
上面这段代码表示可以解析 html 字符串,那也可以响应页面。
如果要处理一些读取出来的 html 字符串,那读文件的时候就指定编码或者调用 data.toString() 方法转为字符。
- 这里因为不处理字符串,所以就不转字符
res.end()
只能接收 二进制数据或者 字符串,其它都报错- 如果传递的字符串,则发送响应的时候,还会自动将字符串转为二进制再发送
- 如果直接就传递的是二进制数据,则直接发送
当客户端浏览器收到发送的响应数据的时:
- 浏览器会先查看响应报文头中的
Content-Type
中的charset
编码,然后根据该编码解析数据 - 如果响应报文头中没有
Content-Type
那么浏览器则根据 HTML 结构中的<meta charset="UTF-8">
来解析数据 - 可以通过
res.writeHead
方法在结束响应之前,写响应头 - 查询网址:http://tool.oschina.net/commons
|
|
处理页面中的动态资源和静态资源
同一个页面中有多个外链,不是指 a 标签。
当浏览器获取到当前响应的 HTML 格式字符串之后,浏览器从上到下依次解析字符串(HTML 结构文档)。
在解析的过程中,如果发现有 link img script iframe 等具有 src 或 href 的标签:a 标签和他们不一样,a 标签是用来跳转的,资源在另一个页面。则,浏览器主动对该资源指向的地址发起请求
|
|
index.html 文档内容
|
|
解决静态资源的 mime 类型
- ‘Content-Type’: mime.lookup(url);
|
|
./views/index.html
|
|
http 和 net 的区别与联系
解释浏览器和服务器的交互本质:
- 本质上就是浏览器通过 Socket 和 服务器 Socket 进行通信
- 双方都通过 HTTP 协议进行交流
- net 模块就是传输层的一个模块,只是为了纯粹的收发数据
- http 模块构建与 net 模块之上,只不过对于收发的数据会进行解析和包装
- 所有的BS模型都是使用的 HTTP 协议进行数据的解析和包装
一下代码仅仅用来说明 net 和 HTTP 之间的联系与区别,没有实际应用意义。
|
|
当在浏览器地址栏输入了一个地址:http://127.0.0.1:3000/
浏览器按照 HTTP 协议将你输入的地址包装成 HTTP 请求报文,内容如下:
|
|
请求报文格式如下:
- 请求头
- 请求首行
- 请求方法 请求路径 HTTP协议版本
- 请求首部字段
- 首都字段中放一些额外的附加信息
- 例如 User-Agent 表示告诉服务器我这个客户端是什么
- 这里为什么有各种浏览器的标识
- 原因在早期的网页有各种各样兼容性问题
- 这个字段还可以用来统计浏览器的使用量占比情况
- Accept
- 早期的 HTTP 0.9 中,只能收发普通字符数据 不支持图片等富文本信息
- 历史原因,现代的服务器和客户端浏览器已经不需要这个东西
- 请求首行
- 空行
- 请求体
- 如果是 post 请求才有请求体
- 如果有请求体,则请求体是在请求头的回车换行之后
- 如果没有,也会有一个空行存在
响应报文:
- 响应头
- 响应首行
- HTTP协议版本 状态码 状态短语
- 响应首部字段
- 响应首行
- 空行
- 响应体
- 所有的响应数据都在响应头之后的空行之后
net 和 http 模块的关系:
- http 模块是构建与 net 模块之上的
- http 中的收发数据还是通过 net 模块中的 Socket 收发数据的
- http 会将收发的数据按照 HTTP 协议自动帮你解析和包装
- 例如 http 模块自动将请求报文解析出来,然后挂载给了 req 请求对象
- 你可以通过 req 请求对象去拿到你想要的信息
- 为什么既有 net 又有 http 呢?
- http 只是一个基于 net 之上的一个模块,该模块遵循的 http 协议
- 会对收发的数据进行 协议格式解析和包装
- HTTP 协议只是适用于B/S模型
- 有的业务功能使用的是别的协议
- 例如 一些智能终端,就用的是别的协议,而不是 HTTP
- 但是他们都是基于最基本的 Socket 网络编程模型而构建的
浏览器的本质
- Socket 客户端
- 收发数据
- 渲染 HTML、CSS
- 解析和执行 JavaScript 代码