一、创建HTTP服务端
// 1、导入http模块
const http = require('http')
// 2、创建服务对象
const server = http.createServer((request,response)=>{
response.end('Hello HTTP Server');//设置响应体,并结束响应
})
// 3、监听端口,启动服务器
server.listen(9000,()=>{
console.log('服务已经启动...');
})
二、HTTP服务端注意事项
- 命令行 ctrl+c 停止服务
- 当服务启动,更新代码必须重启服务才生效
- 响应内容中文乱码的解决办法:添加 response.setHeader('content-type',"text/html;charset=utf-8")语句
// 1、导入http模块
const http = require('http')
// 2、创建服务对象
const server = http.createServer((request,response)=>{
// 中文出现乱码是由于字符集出现问题 :你好变成浣犲ソ
response.setHeader('content-type',"text/html;charset=utf-8")
response.end('你好 HTTP Server');//设置响应体,并结束响应
})
// 3、监听端口,启动服务器
server.listen(9000,()=>{
console.log('服务已经启动...');
})
- 端口被占用
- HTTP协议默认端口是80,HTTPS协议的默认端口是443,HTTP服务开发常用端口3000,8080,8090,9000等【打开资源管理器进行端口关闭】
三、浏览器查看HTTP报文
四、获取HTTP请求报文
使用request对象
| 含义 | 语法 |
|---|---|
| 请求方法 | request.method |
| 请求版本 | request.httpVersion |
| 请求路径 | request.url |
| URL路径 | requiret('url').parse(request.url).pathname |
| URL查询字符串 | require('url').parse(request.url,true).query |
| 请求头 | request.headers |
| 请求体 | request.on('data',function(chunk){}) request.on('end',function(){}) |
注意事项
- request.url只能获取路径以及查询字符串,无法获取URL中的域名以及协议的内容
- request.headers将请求信息转化成一个对象,并将属性名转化了小写
- 关于路径:如果访问网站的时候,只填写了IP地址或者域名信息,此时请求的路径为“/”
- 关于favicon.ico:这个请求是属于浏览器自动发生的请求
// 1、导入http模块
const http = require('http')
// 2、创建服务对象
const server = http.createServer((request,response)=>{
// 1、获取请求方法
console.log(request.method);
//GET
//GET
// 2、获取请求的url,只包含url中的路径与查询字符串
console.log(request.url);
// /
// 3、获取http协议的版本号
console.log(request.httpVersion);
// 1.1
// 4、获取http的请求头
console.log(request.headers);
// {
// host: '127.0.0.1:9000',
// 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/118.0',
// accept: 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8',
// 'accept-language': 'zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2',
// 'accept-encoding': 'gzip, deflate, br',
// dnt: '1',
// connection: 'keep-alive',
// cookie: 'Hm_lvt_d7c7037093938390bc160fc28becc542=1696589624',
// 'upgrade-insecure-requests': '1',
// 'sec-fetch-dest': 'document',
// 'sec-fetch-mode': 'navigate',
// 'sec-fetch-site': 'none',
// 'sec-fetch-user': '?1'
// }
// 5、获取http请求头里的某个键值
console.log(request.headers.host);
// 127.0.0.1:9000
response.end('Server');//设置响应体,并结束响应
})
// 3、监听端口,启动服务器
server.listen(9000,()=>{
console.log('服务已经启动...');
})
五、获取请求体
<body>
<form action="http:127.0.0.1:9000" method="post">
<input type="text" name="name">
<input type="text" name="age">
<button type="submit">提交</button>
</form>
</body>
const http = require('http')
const server = http.createServer((request,response)=>{
response.setHeader('content-type','text/html;charset=utf-8')
// 1、声明一个变量
let body = '';
// 2、绑定data事件
request.on('data',chunk=>{
body+=chunk
})
// 3、绑定end事件
request.on('end',()=>{
console.log(body);
// name=yt&age=111
// 4、设置响应
response.end('Hello HTTP')
})
})
server.listen(9000,()=>{
console.log("服务器已启动...");
});
六、获取请求路径与查询字符串
方式一:导入url模块
- 解析url:url.parse(request.url,true)
- 获取url:url.parse(request.url,true).pathname
- 查询指定参数【注意:url.parse(request.url,true)中要加入true】:url.parse(request.url,true).query.name
// 导入http模块
const http = require('http');
// 导入url模块
const url = require('url');
// 创建服务器对象
const server = http.createServer((request,response)=>{
// 当我路径输入 http://127.0.0.1:9000/?name=yt&age=14
console.log(request.url);
// /?name=yt&age=14
// /favicon.ico
// 解析路径参数(解析request.url)[true是为了更好的解析url拼接的参数]
let res = url.parse(request.url,true)
console.log(res);
// Url {
// protocol: null,
// slashes: null,
// auth: null,
// host: null,
// port: null,
// hostname: null,
// hash: null,
// search: '?name=yt&age=14',
// query: 'name=yt&age=14',
// pathname: '/',
// path: '/?name=yt&age=14',
// href: '/?name=yt&age=14'
// }
// 获取url
let pathname = res.pathname
console.log(pathname);
// /
// 查询字符串
let name = res.query.name
console.log(name);
response.end('url')
})
// 监听端口,启动服务器
server.listen(9000,()=>{
console.log("服务器已启动");
})
方式二:实例化URL对象
- 解析url: new URL(request.url,"http://127.0.0.1")
- 获取url:new URL(request.url,"http://127.0.0.1").pathname
- 查询指定参数【注意:searchParams获取参数要使用get方法】:new URL(request.url,"http://127.0.0.1").searchParams.get('name')
// 导入http模块
const http = require('http');
// 创建服务器对象
const server = http.createServer((request,response)=>{
// 当我路径输入 http://127.0.0.1:9000/?name=yt
let url = new URL(request.url,"http://127.0.0.1")
console.log(url);
// URL {
// href: 'http://127.0.0.1/?name=yt',
// origin: 'http://127.0.0.1',
// protocol: 'http:',
// username: '',
// password: '',
// host: '127.0.0.1',
// hostname: '127.0.0.1',
// port: '',
// pathname: '/',
// search: '?name=yt',
// searchParams: URLSearchParams { 'name' => 'yt' },
// hash: ''
// }
console.log(url.pathname);
// /
// 获取指定参数
console.log(url.searchParams.get('name'));
// yt
response.end('url')
})
// 监听端口,启动服务器
server.listen(9000,()=>{
console.log("服务器已启动");
})
七、实现指定路径和方法进入(登录和注册为例)
// 1、导入http模块
let http = require('http');
// 2、创建服务对象
const server = http.createServer((request,response)=>{
// 解决中文乱码问题
response.setHeader("content-type",'text/html;charset=utf-8')
// 获取请求方法
let {method} = request;
// 获取请求的url路径
let {pathname} = new URL(request.url,'http://127.0.0.1')
// console.log(method);
// console.log(pathname);
// GET
// /login/
// GET
// /favicon.ico
// 判断
if(method === 'GET' && pathname === '/login')
{
// 登录的情形
response.end('登录页面')
}else if(method === 'GET' && pathname === '/register'){
// 注册情形
response.end('注册界面')
}else{
response.end('Not Found')
}
response.end('practice');
});
// 3、监听端口 启动服务
server.listen(9000,()=>{
console.log("服务器已经启动");
})
八、设置HTTP的响应报文
// 1、导入http模块
let http = require('http');
// 2、创建服务对象
const server = http.createServer((request,response)=>{
// 1、设置响应状态码
request.statusCode = 200;
// 2、设置响应描述
request.statusMessage = "requestDescribe";
// 3、设置响应头(可以设置自定义的响应头)
response.setHeader('content-type','text/html;charset=utf-8')
// 4、设置多个同名的响应头
response.setHeader('similar',[1,2,3])
// 5、设置响应体:response.write(可以多次调用
//(如果设置response.write(),一般不会在设置response.end()里的内容)
response.write("xyt")
response.end('practice');
});
// 3、监听端口 启动服务
server.listen(9000,()=>{
console.log("服务器已经启动");
})
案例1:响应文件内容为html、css、js的文件(麻烦)
// 1、导入http模块
let http = require("http");
// 2、创建服务器对象
const server = http.createServer((request, response) => {
response.end(`<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
td{
background-color:red;
}
</style>
</head>
<body>
<table border="1"><tr><td>test</td></tr></table>
</body>
<script>
</script>
</html>`); //设置响应
});
// 监听端口,启动服务器
server.listen(9000, () => {
console.log("服务器已经启动......");
});
案例2:响应文件内容为html、css、js的文件(解决案例1的麻烦问题,更新页面方便,响应方便) 第一步:创建html文件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
td {
background-color: red;
}
</style>
</head>
<body>
<table border="1">
<tr>
<td>test</td>
</tr>
</table>
</body>
<script>
</script>
</html>
第二步:导入html文件
// 1、导入http模块
let http = require("http");
// 2、导入fs模块
let fs = require("fs");
// 3、创建服务器对象
const server = http.createServer((request, response) => {
// 读取文件的内容
let html=fs.readFileSync('./http.html')
//设置响应end()可以传的参数类型为字符串或者buffer
response.end(html);
});
// 监听端口,启动服务器
server.listen(9000, () => {
console.log("服务器已经启动......");
});
九、网页资源的加载的基本的过程
浏览器并发获取请求 html -> css -> img -> js
十、实现网页引入外部资源(麻烦)
// 1、导入http模块
let http = require("http");
// 2、导入fs模块
let fs = require("fs");
// 3、创建服务器对象
const server = http.createServer((request, response) => {
//获取请求的url的路径
let { pathname } = new URL(request.url,'http://127.0.0.1');
if (pathname === "/") {
// 读取html文件的内容
let html = fs.readFileSync(__dirname, "./http.html");
//设置响应end()可以传的参数类型为字符串或者buffer
response.end(html);
} else if (pathname === "./http.css") {
// 读取css文件的内容
let css = fs.readFileSync(__dirname, "./http.css");
//设置响应end()可以传的参数类型为字符串或者buffer
response.end(css);
} else if (pathname === "./http.js") {
// 读取css文件的内容
let js = fs.readFileSync(__dirname, "./http.js");
//设置响应end()可以传的参数类型为字符串或者buffer
response.end(js);
}else{
response.statusCode = 404
response.end('<h1>404 Not Found</h1>');
}
});
// 监听端口,启动服务器
server.listen(9000, () => {
console.log("服务器已经启动......");
});
十一、静态资源与动态资源
静态资源:内容长时间不发生改变的资源。【图片、视频、css文件、JS文件、HTML文件、字体文件】 动态资源:内容经常更新的资源。【百度首页、网页首页、京东搜索列表页面等】
十二、搭建静态资源服务
// 1、导入http模块
let http = require("http");
// 2、导入fs模块
let fs = require("fs");
// 3、创建服务器对象
const server = http.createServer((request, response) => {
//获取请求的url的路径
let { pathname } = new URL(request.url,'http://127.0.0.1');
// 拼接文件路径
let filePath = __dirname+'/page'+pathname;
// 读取文件fs异步API
fs.readFile(filePath,(err,data)=>{
if (err) {
response.statusCode = 500;
response.end('文件读取失败');
return;
}
// 响应文件内容
response.end(data);
})
});
// 监听端口,启动服务器
server.listen(9000, () => {
console.log("服务器已经启动......");
});
十三、静态资源目录与网站根目录
HTTP服务在哪个文件夹中寻找静态资源,那个文件夹就是静态资源目录(网站根目录)。
// 1、导入http模块
let http = require("http");
// 2、导入fs模块
let fs = require("fs");
// 3、创建服务器对象
const server = http.createServer((request, response) => {
//获取请求的url的路径
let { pathname } = new URL(request.url,'http://127.0.0.1');
// 声明一个变量,存储网站的根目录
let root = __dirname + '/page';
// 拼接文件路径
let filePath = root + pathname;
// 读取文件fs异步API
fs.readFile(filePath,(err,data)=>{
if (err) {
response.setHeader('content-type','text/html;charset=utf-8')
response.statusCode = 500;
response.end('文件读取失败');
return;
}
// 响应文件内容
response.end(data);
})
});
// 监听端口,启动服务器
server.listen(9000, () => {
console.log("服务器已经启动......");
});
十四、网站中的URL
网页中的URL主要分为两大类:相对路径与绝对路径
1、绝对路径
绝对路径可靠性强,而且相对容易理解,在项目中运用较多
| 形式 | 特点 |
|---|---|
| atguihu.com/web | 直接向目标资源发送请求,容易理解。网站的外链会用到此形式 |
| //atguihu.com/web | 与页面URL的协议拼接形成完整的URL再发生请求。大型网站用的比较多(方便更改域名或IP地址) |
| /web | 与页面URL的协议、主机名、端口拼接形成完整URL再发送请求。中小型网站 |
2、相对路径
相对路径在发送请求时,需要与当前页面URL路径进行计算,得到完整URL后,再发生请求,学习阶段用的较多。 相对路径不可靠,它是以当前路径为准,当前路径出现问题可能会导致请求不到资源。 例如当前网页URL为 www.atguihu.com/course/h5.h…
| 形式 | 最终的URL |
|---|---|
| ./css/app.css | www.atguihu.com/course/css/… |
| js/app.js | www.atguihu.com/course/js/a… |
| ../img/log.png | www.atguihu.com/course/img/… |
| ../../mp4/show.mp4 | www.atguihu.com/mp4/show.mp… |
3、网页URL的使用场景
a标签的href link标签href script标签src img标签src video audio 标签src form中的action AJAX请求中的URL
十五、设置MIME类型(资源类型)
媒体类型(通常称为Multipurpose Internet Mail Extensions 或MIME类型)是一种标准,用来表示文档、文件或字节流的性质和格式
mime类型结构:【type】/【subType】
例如:text/html text/css image/jpg image/png application/json
HTTP服务可以设置响应头Content-Type来表明响应体的MIME类型,浏览器会根据该类型决定如何处理资源
以下是常见文件对应的mime类型 html:'text/html' css:'text/css' js:'text/javascript' png:'image/png' jpg:'image/jpeg' gif:'image/gif' mp4:'video/mp4' json:'application/json' 对于未知的资源类型,可以选择applicstion/octet-stream类型,浏览器在遇到该类型的响应时,会对响应体内容进行独立存储,也就是我们常见的下载效果。
// 1、导入http模块
const http = require("http");
// 2、导入fs模块
const fs = require("fs");
const path = require("path");
// 声明一个变量
let mime = {
html: "text/html",
css: "text/css",
js: "text/javascript",
png: "image/png",
jpg: "image/jpeg",
gif: "image/gif",
mp4: "video/mp4",
json: "application/json",
};
// 3、创建服务器对象
const server = http.createServer((request, response) => {
//获取请求的url的路径
let { pathname } = new URL(request.url, "http://127.0.0.1");
// 声明一个变量,存储网站的根目录
let root = __dirname + "/page";
// 拼接文件路径
let filePath = root + pathname;
// 读取文件fs异步API
fs.readFile(filePath, (err, data) => {
if (err) {
response.setHeader("content-type", "text/html;charset=utf-8");
response.statusCode = 500;
response.end("文件读取失败");
return;
}
// 获取文件的后缀名
let ext = path.extname(filePath).slice(1);
// 获取对应的类型
let type = mime[ext]
if (type) {
// 匹配到了
//解决乱码问题charset=utf-8的优先级高于html里的meta
// response.setHeader('content-type',type+';charset=utf-8');
if(ext === 'html')
{
response.setHeader('content-type',type+';charset=utf-8');
}else{
response.setHeader('content-type',type);
}
}else{
// 没有匹配到
response.setHeader('content-type','application/octet-stream');
}
// content-type的内容不能写死,可能会出现请求类型混乱
// response.setHeader('content-type','dd')
// 响应文件内容
response.end(data);
});
});
// 监听端口,启动服务器
server.listen(9000, () => {
console.log("服务器已经启动......");
});
十六、完善错误请求
// 1、导入http模块
const http = require("http");
// 2、导入fs模块
const fs = require("fs");
const path = require("path");
// 声明一个变量
let mime = {
html: "text/html",
css: "text/css",
js: "text/javascript",
png: "image/png",
jpg: "image/jpeg",
gif: "image/gif",
mp4: "video/mp4",
json: "application/json",
};
// 3、创建服务器对象
const server = http.createServer((request, response) => {
if (request.method !== 'GET') {
response.statusCode = 405;
response.end('<h1>405 Not Allowed</h1>');
return;
}
//获取请求的url的路径
let { pathname } = new URL(request.url, "http://127.0.0.1");
// 声明一个变量,存储网站的根目录
let root = __dirname + "/page";
// 拼接文件路径
let filePath = root + pathname;
// 读取文件fs异步API
fs.readFile(filePath, (err, data) => {
if (err) {
//设置字符集
response.setHeader("content-type", "text/html;charset=utf-8");
// 判断错误的代号
switch (err.code) {
case "ENOENT":
response.statusCode = 404;
response.end("<h1>404 Not Found</h1>");
case 'EPERM':
response.statusCode = 403;
response.end("<h1>403 Not Found</h1>");
default:
response.statusCode = 500;
response.end("<h1>Internal Server Error</h1>");
}
return;
}
// 获取文件的后缀名
let ext = path.extname(filePath).slice(1);
// 获取对应的类型
let type = mime[ext];
if (type) {
// 匹配到了
//解决乱码问题charset=utf-8的优先级高于html里的meta
// response.setHeader('content-type',type+';charset=utf-8');
if (ext === "html") {
response.setHeader("content-type", type + ";charset=utf-8");
} else {
response.setHeader("content-type", type);
}
} else {
// 没有匹配到
response.setHeader("content-type", "application/octet-stream");
}
// content-type的内容不能写死,可能会出现请求类型混乱
// response.setHeader('content-type','dd')
// 响应文件内容
response.end(data);
});
});
// 监听端口,启动服务器
server.listen(9000, () => {
console.log("服务器已经启动......");
});
十七、GET和POST场景与区别
1、场景
GET:
- 在地址栏直接输入url访问
- 点击a链接
- link标签引入css
- script标签引入js
- video与audio引入多媒体
- img标签引入图片
- form标签中的method为get(不区分大小写)
- ajax中的get请求 POST
- form标签中的method为post(不区分大小写)
- AJAX的post请求
十八、GET和POST请求的区别
GET和POST是HTTP协议请求的两种方式,主要有如下几个区别
- 作用:GET请求数据,POST提交数据。
- 参数位置:GET带参数请求是将参数拼接到URL之后,POST带参数请求是将参数放在请求体中。
- 安全性:POST请求(可抓包)相对GET安全,因为GET的请求会暴露在地址栏上。
- 大小限制:GET请求大小有限制,一般为2K,而POST请求则没有大小的限制。