TCP
tcp是一种面向连接的、可靠的、基于字节流的传输层通信协议
http websocket都是基于tcp协议的
// node提供的net
let net = require('net');
// 创建服务,传入一个socket (回调写法)
// net.createServer(function(socket){ … }).listen(3000);
// 第二种写法 (事件写法)
let server = net.createServer();
// 链接到来时执行 传入socket对象
server.on('connection',function(socket){
// socket没有规则 http基于socket
console.log('链接成功');
});
// localhost:3000
server.listen(3000);
复制代码
此时我们打开localhost:3000,发现浏览器一直在等待
因为我们没有写header,浏览器无法识别
let net = require('net');
let server = net.createServer();
server.on('connection',function(socket){
/
});
// localhost:3000
server.listen(3000);
复制代码
获得以下信息
GET / HTTP/1.1
Host: localhost:3000
Connection: keep-alive
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,/;q=0.8
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9
但是浏览器依旧没反应,因为浏览器请求有一个header,当你返回时,也要有个header
模拟http
curl -v https://www.baidu.com
我们的请求
GET / HTTP/1.1
Host: www.baidu.com
User-Agent: curl/7.54.0
Accept: /
网站的返回
HTTP/1.1 200 OK
Accept-Ranges: bytes
Cache-Control: private, no-cache, no-store, proxy-revalidate, no-transform
Connection: Keep-Alive
Content-Length: 2443
Content-Type: text/html
…
我们就模拟http请求
let net = require('net');
let server = net.createServer();
server.on('connection',function(socket){
socket.setEncoding('utf8');
// 返回一个header
socket.write(`
HTTP/1.1 200 OK
Content-Length: 14
<h1>hello</h1>
`);
});
server.listen(3000);
复制代码
然后重启服务,打开localhost:3000,看到了大大的hello,我们就完成了tcp链接
HTTP
http版本1.0、http1.1和http2.0的区别
- http1.0每次进行通信,都会再次建立一个tcp连接。服务端需要声明keep-alive参数以建立长连接,用来解决性能问题
http1.1开始默认建立长链接(keep-alive) - http1.1开始,建立连接后,一开始服务端只接收header信息,当允许访问啧返回100(临时响应),不允许返回401(未授权)
当返回100时,服务端再传输body信息 - http1.1必须要有host域,而http1.0不存在host域
- http2.0采用多路复用技术,大大增加了并发请求的数量
- http2.0支持用hpack算法压缩header
- http2.0在增加了一次二进制分帧,将http1.0的header分为Headers层,body分为Data层。
将两者用二进制的格式传输 - http2.0采用ssl加密传输,更加安全
而http1.1是明文传输
……
HTTP管线化(HTTP pipelining)
- 管线化就是将多个请求打包同时发送给服务器,并且无需等待服务器响应就可以发送下一个请求
- 只有GET和HEAD请求支持管线化
- 由于管线化基于长链接,不支持http1.0
URI、URN和URL
- URI(Uniform Resource Identifier),统一资源标识符
- URN(Uniform Resource Name),统一资源命名符
- URL(Uniform Resource Locator),统一资源定位符
- 网址(url)http://user:password@www.example.com:80/dist/index.html?a=1&b=2#hash,其中hash值服务器获取不到
内容 | 内容意义 |
---|---|
http | 协议类型 |
user:password | 登录信息 |
www.example.com | 服务器地址 |
80 | 服务器端口号 |
/dist/index.html | 文件路径 |
a=1&b=2 | 查询字符串 |
hash | 片段标识符 |
node的url模块自带解析网址的方法
let url = require('url');
let str = 'http://user:password@www.example.com:80/dist/index.html?a=1&b=2#hash';
let obj = url.parse(str,true);
console.log(obj);
复制代码
得出以下内容
Url {
protocol: 'http:',
slashes: true,
auth: 'user:password', // 用户信息
host: 'www.example.com:80',
port: '80',
hostname: 'www.example.com',
hash: '#hash',
search: '?a=1&b=2',
query: { a: '1', b: '2' },
pathname: '/dist/index.html',
path: '/dist/index.html?a=1&b=2',
href: 'http://user:password@www.example.com:80/dist/index.html?a=1&b=2#hash' }
复制代码
我们可以用obj.query[属性名]
来获取数据
http请求、响应内容
http请求
- http请求由客户端发起
- 由请求行、请求头、请求体组成
请求行包括请求方法、URI、协议版本 请求方法包括:
GET 获取
POST 发送
PUT 传输文件
HEAD 获取报文首部
DELETE 删除
OPTIONS 询问支持的方法
……
HTTP响应
- http响应由服务端发起
- 由响应行、响应头、响应体组成
响应行包括协议版本、状态码、状态码原因短语
2XX 成功
200 OK 数据正常被处理
204 Not Content 响应正常,无实体
206 Partial Content 范围请求,返回部分数据3XX 重定向
301 Moved Permanently 永久重定向
302 Found 临时重定向
303 See Other 和302类似,但必须用GET方法
304 Not Modified 状态未改变
307 Temporary Redirect 临时重定向,不该改变请求方法4XX 客户端错误
400 Bad Request 请求报文语法错误
401 unauthorized 需要认证
403 Forbidden 服务器拒绝访问
404 Not Found 服务器未找到资源5XX 服务器端错误
500 Internal Server Error 服务器故障
503 Service Unavailable 服务器处于超负载或正在停机维护
HTTP应用
// node自带的http方法
let http = require('http');
// 创建server
let server = http.createServer();
// request事件监听
server.on('request',function(req,res){
// socket被封装为req(可读流),res(可写流)
// req代表请求,res代表响应
console.log('请求方法',req.method);
console.log('请求路径',req.url);
console.log('http版本',req.httpVersion);
console.log('请求头',req.headers);
// 获取数据
let arr = [];
// req是可读流
req.on('data',function(data){
arr.push(data);
});
req.on('end',function(){
// 获取读出来的数据
console.log('数据',Buffer.concat(arr).toString());
});
// 响应
// 设置响应头
res.setHeader('Content-Type','text');
res.setHeader('a','1');
res.end('<h1>Hello World</h1>');
});
// tcp的方法依旧存在
server.on('connection',function(socket){
console.log('连接成功')
})
server.listen(3000);
复制代码
执行后,打开localhost:3000
终端显示如下
请求方法 GET
请求路径 /
http版本 1.1
请求头 { host: 'localhost:3000',
connection: 'keep-alive',
'upgrade-insecure-requests': '1',
'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36',
accept: 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8',
'accept-encoding': 'gzip, deflate, br',
'accept-language': 'zh-CN,zh;q=0.9' }
数据
复制代码
浏览器显示如下
正向代理和反向代理
正向代理
- 正向代理就是客户端A想要访问服务器B但是无法访问,然后寻找代理服务器,通过代理服务器C访问服务器B,翻墙就是个很好的例子
对于服务器B来说不知道客户端A的存在
- 反向代理就是客户端A想要访问www.baidu.com,其实A访问到的是代理服务器B,由代理服务器去访问原始服务器C或D或E……
对于客户端A来说不知道服务器C或D或E……的存在