一、请求与响应模型
- 服务器(server)是个没有显示器的电脑,拥有一个IP地址和端口。
- 客户端(浏览器)也拥有一个IP地址。
- 客户端会发送一个请求给服务器的IP地址的一个端口上,而服务器接收到请求后会在同一端口把响应返回到客户端的IP地址上去。
二、体系化学习HTTP
- 必须学会
- 基础概念:请求+响应
- 如何调试(用的是Node.js,可以用log / debugger)
- 在哪查资料(用的是Node.js,看Node.js文档)
- 标准制定者(HTTP 规格文档: RFC 2612等)
- 如何学
- Copy-抄文档、抄老师
- Run-放在自己的机器上运行成功
- Modify-加入一点自己的想法,然后重新运行
三、基础概念
(一)请求Request
1、请求的构成
①请求行Request-Line
请求动词 路径加查询参数 协议名/版本
- 例如GET / HTTP/1.1
- 如果路径加查询参数未写,就会自动补上根路径/
- 请求动词有GET(获取内容)/POST(上传内容)/PUT/PATCH/DELETE等
②请求头Requset Header
- Host:请求的域名或者IP+端口号
- Accept:text/html ——告诉服务器我想要的文本类型
- User-Agent:用户代理,帮你发请求的工具,可以为Chrome或者curl
- Content-Type:请求体的格式
- referer:发请求的url
③回车——隔开请求头和请求体
④请求体Request Body
- 请求体为上面Content-Type的规定的格式的任意内容
- 请求体在GET请求中一般为空
- 请求体在POST请求中为上传内容
2、如何发送请求(都是用url,请求的都是url,就算你就写了个域名,也会自动补成url)
(1)用Chrome地址栏发请求
(2)用curl发送请求curl URL
例如curl -v http://127.0.0.1:8888
- 设置请求动词
- 默认是GET
- 改成POST:添加-X POST(注意大写)
- 例如
curl -v -X POST http://127.0.0.1:8888
- 设置路径和查询参数
- 直接在url后面加
- 例如
curl -v -X POST http://127.0.0.1:8888/xxxx?wd=hi
- 设置请求头
-H 'Name: Value'或者--header 'Name: Value'- 例如
curl -v -H 'Accept: text/html' http://127.0.0.1:8888我想要HTML
- 设置请求体
-d '内容'或者--data '内容'curl -v -H 'Content-Type: text/plain;charset=utf-8' -d '请求体内容' http://127.0.0.1:8888我要上传的内容是纯文本,上传的内容为“请求体内容”
3、如何查看或读取请求
(1)用Chrome开发者工具查看请求的信息
开发者工具 → Network → 点击要查看的请求 → Headers → Requset Header → view source
(2)用curl发请求时就可看到请求信息
(3)用Node.js读取请求的所有信息
- 读取请求动词
console.log("method:");
console.log(method);
- 读取路径
request.url路径,带查询参数path纯路径,不带查询参数query只有查询参数
console.log("请求路径(带查询参数):");
console.log(pathWithQuery);
- 读取请求头
console.log("request.headers");
console.log(request.headers);
request.headers['Accept']
- 读取请求体
比较复杂,先不讲
(二)响应
1.响应的构成
①状态行
协议名/版本 状态码 状态字符串
- 状态码:200表示请求的路径服务器是知道的;404表示请求的路径服务器不知道
②响应头Response Headers
- Content-Type:响应体的格式“类型/语法”
③回车——隔开响应头响应体
④响应体
- 响应体为返回给客户端的内容
- 响应体一般为下载内容
2、用Node.js设置响应
①设置响应状态码
response.statusCode = 200;
②设置响应头
response.setHeader('Content-Type', 'text/html');
③设置响应体
response.write('内容');
可追加内容
④设置结束响应
response.end()表示响应可以发给用户了
3、如何查看响应
(1)用Chrome开发者工具查看响应的信息
开发者工具 → Network → 点击要查看的请求 → Headers → Reponse Header → view source
(2)用curl发请求时就可看到响应的信息
四、如何做出一个响应--做一个服务器
(一)做法
需用编程,Node.js有一个http模块可以做到。
(二)步骤
这些代码就是服务器代码,就像百度的服务器,就是我们下面这个代码更复杂一点罢了,但是都是放在服务器上,而不是像我们这样放在自己的电脑上。因为我们暂时没有服务器。
1、用VSCode新建文件server.js,并写入以下代码。这时文件server.js相当于一个服务器了。
2、代码如下
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')
response.write(`二哈`)
response.end()
} else if(path === '/x'){
response.statusCode = 200
response.setHeader('Content-Type', 'text/css;charset=utf-8')
response.write(`body{color: red;}`)
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)
3、解释
每次收到请求都会把中间的代码执行一遍
(1)输出请求的路径(带查询参数),具体表现为“有个傻子发请求过来啦!路径(带查询参数)为:/xxxx”
(2)用if else判断路径,并返回相应的响应
①如果是已知路径,一律返回200
-
如果路径为/,那么状态码是200,响应头为响应体的格式是“text类型html语法,编码方式是utf-8”,响应体的内容也就是返回的内容为“二哈”,响应结束。
-
如果路径为/x,那么状态码是200,响应头为响应体的格式是“text类型css语法,编码方式是utf-8”,响应体的内容也就是返回的内容为“body{color: red;}”,响应结束。
②如果是未知路径,一律返回404
-
状态码是404,响应头为响应体的格式是“text类型html语法,编码方式是utf-8”,响应体的内容也就是返回的内容为“你输入的路径不存在对应的内容”,结束响应。
4、node server.js 8888来启动服务器
- 服务器开了一个端口8888,这个端口就被server.js(也就是服务器)监听了。
- 这时,只要有人请求了8888,就会进入服务器的代码里面
- 每请求一次,服务器里的代码就会运行一次
5、成为一个完整网页的全过程
- 一个路径返回HTML字符串,一个路径返回CSS字符串,一个路径返回JS字符串。
- 在HTML字符串中通过
link把CSS字符串和JS字符串的路径结合起来。 - 当浏览器读到
link时就会再去请求CSS字符串的路径和JS字符串的路径 - 这就是HTML和CSS和JS通过HTTP传送并结合到浏览器成为一个完整网页的全过程。
- 以下为例子:把上面代码修改了一点
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");
response.write(`
<!DOCTYPE html>
<head>
<link rel="stylesheet" href="/x">
</head>
<body>
<h1>标题</h1>
</body>
</head>
`);
response.end();
} else if (path === "/x") {
response.statusCode = 200;
response.setHeader("Content-Type", "text/css;charset=utf-8");
response.write(`body{color: red;}`);
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
);
如果路径是/,那么就返回一串HTML字符串,其中有句代码为<link rel="stylesheet" href="/x">。当浏览器渲染这些HTML代码,读到link这句时,就要再去请求路径为/x的CSS字符串。然后CSS就会作用到HTML代码上了。
五、console.log调试大法
- 适用于JS
- 把你认为正确的语句写进去,看看运行出来是啥样的。
六、小知识点
- 代码
- ``(1的左边)这种字符串里面可以回车
- ''(Enter的左边)这种字符串里面要回车只能用\n表示
- curl不光可以发HTTP请求,它可以完成浏览器的基本功能,比如下载图片等,就是没有可视化。相当于命令行和图形界面的关系
- 不管状态码是200还是404,响应体照样会返回。只是平常的404里的响应体都为空
else {
response.statusCode = 404;
response.end();
所以我们才会看到“找不到xxx页面”,这是Chrome发现服务器返回了404却没有返回其他内容,于是Chrome就自己做了个网页给我们看。 4. HTTP里所有路径以/开头
七、购买自己的服务器
- 我们在阿里巴巴上有一个云服务器,里面有两个用户root和frank。
- root的家目录是/root frank的家目录是/home/frank
- 在本地用
ssh root@IP进入root用户的家目录 - 用
ssh frank@IP进入frank用户的家目录
(具体见PPT18)
八、常见状态码
HTTP状态码由三个十进制数字组成,第一个十进制数字定义了状态码的类型,后两个数字没有分类的作用。
HTTP状态码分类
- 1** ——信息,服务器收到请求,需要请求者继续执行操作
- 2** ——成功,操作被成功接收并处理
- 3** ——重定向,需要进一步的操作以完成请求
- 4** ——客户端错误,请求包含语法错误或无法完成请求
- 5** ——服务器错误,服务器在处理请求的过程中发生了错误