HTTP详解

317 阅读5分钟

七层网络协议 (理想情况下的分层)

  • 应用层

  • 表示层

  • 会话层 -> 应用层 http

  • 传输层 -> TCP / UDP

  • 网络层 -> ip

  • 数据链路层 -> 交换机 集线器 -> 物理层

  • 物理层 网线 同轴电缆

下层是为了上层服务的 HTTP应用层 (header头) 数据传递怎么去传递数据和解析数据。

mac地址 (固定的) ip地址 (可变的) mac地址可以定位到具体的位置 来进行数据的传输 在出厂网卡的时候 会给你分配一个mac地址 (自己做的唯一 ,原则上唯一不可以更改) 最终通信都是通过mac地址 mac地址比较长 -》 ip来表示 -》 通过ip来进行寻址mac地址

客户端访问服务端的基本流程

  • 用户会输入一个网址 通过DNS解析服务端找到对应的ip地址

  • 需要将数据传递给对方 http中存的是报文 ( 请求行 请求头 请求体)

  • tcp来发送数据 对数据进行拆包 而且添加了序号 (为了服务器收到之后可以进行数据的重组) 端口号 (tcp严重的缺陷队头阻塞,如果没有收到队头的数据,不会发送后续的内容)

  • 发送的时候 需要通过ip地址进行寻址操作 边转发边发送 经历多个路由器 发快递 北京 -> 南京 -》 杭州 -》 上海 (路由)

  • 对方会根据 我们的数据进行重组 将数据拼接起来 最终服务器会响应客户端说 数据收到了 (响应行, 响应头,响应体)

http缺陷 1.1

  • 安全问题 在传输中明文传输 (http 现在使用最多的就是1.1 ) 明文就会被别人篡改 对方也不知道这个数据有被更改过 tls 来保证数据的可靠。 通过证书来保证数据不被篡改 https 就解决了 http的问题
  • http 1.1 也有个缺陷就是 基于tcp的 tcp层面上有一个队头阻塞问题。 http1.1 本身就有这个问题 (tcp面向连接 慢 三次握手和四次断开)

中新增的特点 1.0 -》 1.1

  • 1.0 缺陷就是只能发送get请求, 而且不支持除了文本之外的内容 图片,css都不支持
  • 1.0 发送的时候会创建tcp连接 发送完毕后就关闭了 性能浪费
  • 不能识别访问者的身份

1.1解决的方式

  • 添加了除了get之外的其他请求方法, 增加了请求头的概念 (发送除文本之外的内容)
  • 长连接的方式 解决发送时创建多个tcp的问题, 在一段时间内可以复用tcp通道
  • 为了可以处理多个请求同时发送,内部还有管线化的特点 ( 可以在一个tcp中发送多个请求 ,问题是响应的时候 需要根据顺序来响应, 依然会有队头阻塞的问题 指的是http中的队头阻塞) 在2.0中被解决了 , tcp的队头阻塞是tcp本身的 所以http2 也无法解决
  • cookie 增加了cookie机制 可以用于识别用户身份 xsrf

options表示跨域的时候 会先检测是否ok ? ok的话再去发送具体的数据 复杂请求才会发送options,常见的基本get和post就是简单请求,添加了自定义的头部就变成了了复杂请求了 只在跨域的时候使用

##错误 502网关错误 503 服务端负载均衡挂掉了。 HTTP状态码 (服务端响应的状态码 服务端响应的) 状态服务端可以随便写 1xx 101 websocket 2xx 200 ok 204 成功但是没有响应内容 206范围请求 3xx 301 永久重定向 (在开发的时候尽可能减少重定向) 302 (临时重定向 , 客户端跳转了) 304 缓存 (面试常问 对比缓存,如果文件没有变化就用缓存) 307 只能用get重定向 4xx 400 客户端访问不正确 404 找不到 401 没有认证权限 403 认证了还是没权限 405 方法服务端不存在 5xx 服务端问题 500 服务端内部

1639300282(1).png

const http = require('http'); // 引入了http模块 


// 请求必须得到响应这一条才算完成 , 否则就是pending状态

// 这里可以创建一个服务端 监听客户端的请求到来
const server = http.createServer((req, res) => { // tcp 来的 node中有自己先是一个传输成模块 net
    // req 代表客户端的请求 
    // res 代表服务端的响应 
    console.log(req.method); // 默认在url输入地址访问就是get请求  方法是大写的
    console.log(req.url);  // /xxxx?a=1   hash值服务端获取不到(前端hash路由无法实现服务端渲染)
    console.log(req.httpVersion); // 版本号 
    // /r/n
    console.log(req.headers); // header都是小写的  key:value
    ///r/n/r/n

    // req是一个可读流, 读取客户的数据

    let arr = [];
    req.on('data',function(chunk){ // tcp 传输会分段 
        arr.push(chunk);
    });
    // push(null)
    req.on('end',function(){ // 整个请求体接受完毕后会触发, 没有请求体也会触发end事件
        console.log(Buffer.concat(arr).toString())
    }); 

    // express koa  都是基于这些特点 扩展出来的 

    // 服务端 
    // res.statusCode = 450;
    // res.statusMessage = 'no exists';
    res.setHeader('name','zf'); // 自定义header   response header
    res.setHeader('Content-Type','text/html;charset=utf-8'); // 防止乱码


    // end 可以放入buffer or String  res 是一个可写流
    res.write('1');
    res.write('2'); // 调用end 表示响应结束  不写就一直loading
    res.end(Buffer.from('珠峰')); 
});
let port = 4000;
// 手动重启  改服务端代码必须重启  开发中nodemon  pm2 
// nodemon node的监控器 监控文件的变化 文件变化后可以自动重启
server.on('error',function(err){
    if(err.code === 'EADDRINUSE'){ // 端口被占用了 
        server.listen(++port); // 底层是基于发布订阅的 监听成功会触发函数执行
    }
})
server.listen(port, function () {
    console.log(`server start ${port}`)
});

// 浏览器就是一个典型的客户端

const http = require('http');

let client = http.request('http://www.baidu.com',{
    'method':'get', // 请求方法
    // 'port':"4000"
},function(res){ // 会响应你
    let arr = [];
    res.on('data',function(chunk){
        arr.push(chunk)
    });
    res.on('end',function(){
        console.log(Buffer.concat(arr).toString())
    })
})
client.end('a=1'); // request方法必须+end才可以发送请求 

pupetter一般是爬虫