欢迎
搞定HTTP请求和响应
要说的话
:本文是用node.js代码实现http,主要是了解用浏览器&curl命令和http服务器之间请求和响应的全过程,前段先会简单了解下请求和响应,后段会系统化地学习HTTP,源码+图文解说。 --资料来源饥人谷
前置条件
我希望你看这篇文章时理解什么是URL路径和查询参数,理解IP和端口。如果不知道,可以看我的http入门笔记1(浅析URL),要操作的话需要安装Node.js
i. 先来简单了解下请求和响应
–图片来源于饥人谷
-
请求就是客户端里的浏览器发送一个请求到服务器
-
响应就是服务器拿到这个请求后在同一个端口返回一个响应
1.1 如何发请求呢
- ①用Chrome地址栏
下图是我输入baidu.com后chrome向www.baidu.com发送的第一个请求
- ②用curl命令
curl是常用的命令行工具,用来请求Web 服务器。它的名字就是客户端(client)的URL 工具的意思
在cmder(或者cmd)里输入
curl -v https://www.baidu.com
可以清楚的看到请求与响应过程
输入命令后可以看到高亮部分上面是加密过程不用管,高亮部分是发送的请求(’>‘部分),高亮下面是返回的响应(’<'部分)
可以看到代理工具使用的是 curl/7.71.1
代理工具概念:
帮你发请求的工具叫做【用户代理】,英文名是User Agent
1.2 如何做出一个响应呢
要求自己用curl发请求自己响应
Node.js有一个http模块可以做到(我也是粘贴复制饥人谷老师的)
下面是node.js代码服务器完整代码,主要看中间部分,完整的代码在https://github.com/woshidw/node-demo1的server.js里也有
var http = require('http')
var fs = require('fs')
var url = require('url')
var port = process.argv[2]
if(!port){
console.log('请指定端口号好不啦?\nnode server.js 8888 这样不会吗?')
process.exit(1)
}
var server = http.createServer(function(request, response){
var parsedUrl = url.parse(request.url, true)
var pathWithQuery = request.url
var queryString = ''
if(pathWithQuery.indexOf('?') >= 0){ queryString = pathWithQuery.substring(pathWithQuery.indexOf('?')) }
var path = parsedUrl.pathname
var query = parsedUrl.query
var method = request.method
/******** 从这里开始看,上面不要看 ************/
console.log('有个傻子发请求过来啦!路径(带查询参数)为:' + pathWithQuery)
/*每次请求都会执行 */
if(path === '/'){
response.statusCode = 200
response.setHeader('Content-Type', 'text/html;charset=utf-8')
/*响应的描述信息,text/html我是文本,语法是heml*/
response.writ console.log('有个傻子发请求过来啦!路径(带查询参数)为:' + pathWithQuery)
/*每次请求都会执行 */
if(path === '/'){
response.statusCode = 200
/*成功返回状态码200*/
response.setHeader('Content-Type', 'text/html;charset=utf-8')
/*响应的描述信息,text/html我是文本,语法是heml*/
response.write(`
<!DOCTYPE html>
<head>
<link rel="stylesheet" href="/x">
</head>
<body>
<h1>如果路径是/,就发送这段内容,格式为html</h1>
<h2>我请求了路径为/x的css
</body>
`)
/* 注意:``和''是不同的,``里可以加回车 ,''里回车用\n表示*/
response.end()
} else if(path === '/x'){
response.statusCode = 200
response.setHeader('Content-Type', 'text/css;charset=utf-8')
response.write(`h2{color: green;}`)
response.end()
} else {
response.statusCode = 404
/*访问的路径不存在返回状态码为404*/
response.setHeader('Content-Type', 'text/html;charset=utf-8')
response.write(`你访问的页面不存在`)
response.end()
}e(`
<!DOCTYPE html>
<head>
<link rel="stylesheet" href="/x">
</head>
<body>
<h1>如果路径是/,就发送这段内容,格式为html</h1>
<h2>我请求了路径为/x的css
</body>
`)
/*浏览器请求了localhost根目录后,发现根目录要请求一个/x的css,
于是再次发送请求请求/x,这就是html和css通过http传送到浏览器的整个过程,
一个路径返回html字符串,一个路径返回css字符串*/
/* 注意:``和''是不同的,``里可以加回车 ,''里回车用\n表示*/
response.end()
} else if(path === '/x'){
response.statusCode = 200
response.setHeader('Content-Type', 'text/css;charset=utf-8')
response.write(`h2{color: green;}`)
response.end()
} else {
response.statusCode = 404
response.setHeader('Content-Type', 'text/html;charset=utf-8')
response.write(`你访问的页面不存在`)
response.end()
}
/******** 代码结束,下面不要看 ************/
})
server.listen(port)
console.log('监听 ' + port + ' 成功\n请用在空中转体720度然后用电饭煲打开 http://localhost:' + port)
做出响应主要就围绕上面中间代码进行探讨
这些代码就是服务器代码,一般放在服务器上
path是不带查询参数的路径/x
query是查询参数的对象形式{a:‘1’}
queryString是查询参数的字符串形式?a=1
pathWithQuery是带查询参数的路径,一般不用
request是请求对象
response是响应对象
1.2.1 响应的代码逻辑
①语法
-
``里面可以回车
-
’ '里面要回车只能用\n表示
②逻辑
- 每次收到请求都会把中间的代码执行一遍用if else判断路径,并返回响应
- 如果是已知路径,一律返回200
- 如果是未知路径,一律返回404
- Content-Type表示内容的「类型/语法」
- response.write()可以填写返回的内容
- response.end()表示响应可以发给用户了
命令行输入cd +相关绝对路径进入文件,输入以下命令显示的效果
跟随链接进入http://localhost:8888后得到的效果
开了一个8888的端口,被node.js监听了,如果有人请求了8888这个端口,就会走入node.js代码里,每一次请求就执行一遍上面的代码,改了服务器代码都要重新启动服务器才可以生效
然后再看服务器显示什么
点击地址访问了路径为/的网页
ii. 系统化学习HTTP
2.1 必须学会什么
- 基础概念(主要是请求和响应)
- 如何调试(通过用Node.js,可以用log / debugger)
- 在哪查资料(用的是Node.js,看Node.js文档)
- 标准制定者是谁(HTTP规格文档:RFC 2612<RFC 2612专门规定http规则>等)
如何学(CRM学习法)
- Copy-抄文档、抄老师
- Run -放在自己的机器上运行成功
- Modify -加入一点自己的想法,然后重新运行
2.2 HTTP基础概念
1) 请求
-
请求动词 路径加查询参数 协议名/版本
-
Host:域名或IP
-
Accept: text/ html
-
Content-Type:请求体的格式
-
回车(请求头和请求体中间加个回车,用于区分)
-
请求体(也就是上传内容,可以是任意内容,但要在请求体格式里写清楚)
细节
①. 三部分:请求行(红色部分重点)、请求头(蓝色部分)、请求体(绿色部分)
②. 请求动词有GET(获取内容)/POST(上传内容)/PUT/PATCH/DELETE等
③. 请求体在GET请求中一般为空
④. 文档位于RFC 2612第五章
⑤. 大小写不敏感(随意)
下图是请求过程
在开发者工具里可以看到请求动词为GET,访问路径为/(没有带查询参数),协议为HTTP,版本号为1.1
Host就是域名和端口号
Accept用来表示接受什么内容,浏览器会默认加上accept就是html或者xhtml+xml或者xml等等(首>先是html,如果没有html也可以接受Xhtml,如过没有Xhtml也可以接受Xml等等)
2) 响应
-
协议名/版本 状态码 状态字符串
-
Content-Type:响应体的格式
-
回车
-
响应体(也就是下载内容)
细节
①三部分:状态行、响应头、响应体
②常见的状态码是考点
③文档位于RFC 2612第六章
下图是响应过程
开头就是HTTP/1.1,协议加版本。200是状态码(200代表ok),ok是对200的解释
Content-Type是响应体的格式为(文本,语法为html,字符编码为UTF-8)
在Response可以看响应体,这部分语法格式在Content-Type写好的,如下
重点记住请求行和状态行,HTTP就很ok了
再记一遍:
- 请求行是:
请求动词 路径(加查询参数) 协议名/版本
- 状态行是:
协议名/版本 状态码 状态字符串
iii. 用curl构造请求
主要代码curl -v http://127.0.0.1:8888
简单的请求
- 设置请求动词
-X POST
curl -v -X POST http://127.0.0.1:8888
可以看到原来的GET变成了POST
注意大小写!!!
- 设置路径和查询参数
直接在url后面加
curl -v -X POST http://127.0.0.1:8888/xxxx?wd=hi
在地址后面加了路径为/xxxx,查询参数为?wd=h1
锚点是不会传到服务器的
- 设置请求头
-H 'Name: Value’或者–header ‘Name: Value’
curl -v -X POST -H 'Accept: text/html' http://127.0.0.1:8888/xxxx?wd=hi
把接受任意改成了要接受html的内容
请求头这里可以设置任何奇奇怪怪的内容,服务器都可以读到,比如
curl -v -X POST -H 'dw: SB' http://127.0.0.1:8888/xxxx?wd=hi
- 设置请求体
-d ‘内容’ 或者–data ‘内容’
一般和POST一起
命令行输入
curl -v -X POST -H 'dw: SB' -H 'Content-Type: text/plain;charset=utf-8' -d '请求体内容' http://127.0.0.1:8888/xxxx?wd=hi
我要上传的内容是纯文本,编码是utf-8,要上传的内容就是’请求体内容’五个字
一般1个汉字两个字节
iv. 用node.js读取构造请求
- 读取请求动词
request.method
console.log('method')
...
console.log('有个傻子发请求过来啦!路径(带查询参数)为:' + pathWithQuery)
/*每次请求都会执行 */
console.log("method:")//method是
console.log(method);//GET或者POST
...
服务器重启后用curl链接curl http://localhost:8888
,服务器得到
用curl构造动词curl -X POST http://localhost:8888
- 读取路径
request.url路径,带查询参数
路径写了的后面,该路径可以被读取,就不演示了
path 纯路径,不带查询参数
query只有查询参数
- 读取请求头
request.headers[‘Accept’]
...
console.log("request.headers:");
console.log(request.headers);//可以通过request.headers拿到所有的请求头
...
用这个 curl -v -H 'dw: SB' http://127.0.0.1:8888
服务器得到所有请求头
- 读取请求体
v. 用node.js设置响应
- 设置响应状态码
response.statusCode = 200
可以改动node.js里response.statusCode = xxx来改动状态码
...
response.statusCode = 200
/*成功返回状态码200*/
...
- 设置响应头
response.setHeader(‘Content-Type’, ‘text/html’);
...
response.setHeader('Content-Type', 'text/htmI');
response.setHeader('dw', 'sb');
...
可以通过上面部分修改响应头
- 设置响应体
response.write(‘内容’)
可追加内容
response.write(`
<!DOCTYPE html>
<head>
<link rel="stylesheet" href="/x">
</head>
`)
response.write(`
<body>
<h1>如果路径是/,就发送这段内容,格式为html</h1>
<h2>我请求了路径为/x的css
</body>
`)
第一次我写head,第二次我写body,可以追加内容,如下,都可以读出来
--continue
学习前端从入门到入土,我正在路上。您的每一次观看,就是对我学习路上最大的鼓励,一起努力吧!
欢迎留下您宝贵的意见。
最后,你可能看累了吧,送上一波福利
–图片来源于网络