HTTP协议
包括请求行、请求头、请求体
http常见请求方法:
url统一资源请求符,其本身也是一个字符串
响应体的内容格式是非常灵活的,常见的响应体格式有:
1.HTML 2.CSS 3. JavaScript 4.图片 5.视频 6.JSON
响应状态码:
IP本身是一个数字标识IP 用来标志网络设备,实现设备间通信
端口:应用程序的数字标识
作用:实现不同主机应用程序之间的通信
响应报文包含响应行,响应头,响应体
HTTP服务注意事项
https默认端口号是443
创建http服务
// 导入http模块
const http=require('http');
// 创建服务对象
// 请求 响应
const server=http.createServer((request,response)=>{
response.setHeader('content-type','text/html;charset=utf-8');//设置响应头
response.end('Hello HTTP Server');//设置响应体
})
// 3.监听端口,启动服务
server.listen(9000,()=>{
console.log('服务已经启动。。。');
})
获取http请求报文
//1. 导入http模块
const http=require('http');
//2.创建服务对象
// 请求 响应
const server=http.createServer((request,response)=>{
// 1.声明一个变量
let body='';
// 2.绑定事件
request.on('data',chunk=>{
body+=chunk;//chunk是buffer,在做加法的时候会转化为字符串
})
// 3.绑定end事件
request.on('end',()=>{
console.log(body);
response.end("Hello http");
})
})
// 3.监听端口,启动服务
server.listen(9000,()=>{
console.log('服务已经启动。。。');
})
提取HTTP请求报文
查找路径和字符串的两种方式
const http=require('http');
// 1.导入url模块
const url=require('url');
const server=http.createServer((request,response)=>{
// 2.解析request.url
let res=url.parse(request.url,true);//第二个属性为true时quire属性将会变成一个对象
// 路径
let pathname=res.pathname;
console.log(pathname);
// 查询字符串
let keyword=res.query.keyword;
console.log(keyword);
response.end('url');
})
server.listen(9000,()=>{
console.log('服务已经启动。。。');
})
const http=require('http');
const server=http.createServer((request,response)=>{
// 实例化url对象
// let url=new URL('http://www.xxx.com/search?a=100&b=200')
// let url=new URL('/search?a=100&b=200','http://127.0.0.1');
let url=new URL(request.url,'http://127.0.0.1');
// 输出路径
console.log(url.pathname);
// 输出keyword查询字符串
console.log(url.searchParams.get('keyword'));
response.end('url new');
})
server.listen(9000,()=>{
console.log('服务已经启动。。。');
})
响应请求练习
const { log } = require('console');
const http=require('http');
const server=http.createServer((request,response)=>{
// 获取请求的方法
// let method=request.method;
let {method}=request;
// 获取请求的url路径
let {pathname}=new URL(request.url,'http://127.0.0.1');
response.setHeader('content-type','text/html;charset=utf-8');
// 判断
if(method==='GET' && pathname==='/reg'){
response.end('注册界面');
}else if(method==='GET' && pathname==='/login'){
response.end('登陆界面');
}else{
response.end('404 Not Found');
}
// response.end('practice');
});
server.listen(9000,()=>{
console.log('服务器已经启动。');
})
设置HTTP的响应报文
write可以多次调用
每一个请求,在处理的时候必须要执行end 方法的,有且只能有一个end方法
write和end 的两种使用情况:
//1.write和end 的结合使用响应体相对分散
response.write('xx');
response.write('xx');
response.write('xx');
response.end();//每一个请求,在处理的时候必须要执行end 方法的
//2.单独使用end 方法响应体相对集中
response.end('xxx');
练习:列表隔行换色
搭建HTTP服务,响应一个4行3列的表格,并且要求表格有隔行换色效果,且点击单元格能高亮显示
const http=require('http');
//引入fs模块
const fs=require('fs');
const server=http.createServer((request,response)=>{
// 读取文件内容
let html=fs.readFileSync(__dirname+'./test.html')
response.end(html);//end()参数可以是Buffer和字符串
})
server.listen(9000,()=>{
console.log('服务已经启动');
})
网页资源加载基本过程
网页资源的加载都是循序渐进的,首先获取HTML的的容,然后解析HTML在发送其他资源的请求,如css,Javascript,图片等。理解了这个丙容对于后续的学习与成长有菲常大的帮助
模块练习:网页资源引入
const http=require('http');
const fs=require('fs');
const server=http.createServer((request,response)=>{
//获取请求url的路径
let {pathname}=new URL(request.url,'http://127.0.0.1');
// 读取文件内容
// 不能写响应头编码,否则没有效果
if(pathname==='/'){
let html=fs.readFileSync(__dirname+'/test.html');
response.end(html);//end()参数可以是Buffer和字符串
}else if(pathname==='/index.css'){
let css=fs.readFileSync(__dirname+'/index.css');
response.end(css);//end()参数可以是Buffer和字符串
}else if(pathname==='/index.js'){
let js=fs.readFileSync(__dirname+'/index.js');
response.end(js);//end()参数可以是Buffer和字符串
}else{
response.statusCode=404;
response.end('<h1>404 Not Found</h1>')
}
})
server.listen(9000,()=>{
console.log('服务已经启动');
})
静态资源服务
静态资源
是指内容长时间不发生改变的资源,例如图片,视频,CSS文件,JS文件,HTML文件,字体文件等
动态资源
是指内容经常更新的资源,例如百度首页,网易首页,京东搜索列表页面等
静态资源目录与网站根目录
HTTP服务在哪个文件夹中寻找静态资源,那个文件夹就是静态资源目录
,也称之为网站根目录
思考:Vscode中使用live-server访问HTML时,它启动的服务网站根目录是谁?
vscode所打开的文件夹
const http=require('http');
const fs=require('fs');
const server=http.createServer((request,response)=>{
//获取请求url的路径
let {pathname}=new URL(request.url,'http://127.0.0.1');
// 声明一个变量
let root=__dirname+'/page';
// let root=__dirname+'/../';//__dirname得到的是当前文件所在的文件夹,../是得到上一级文件夹
// 拼接文件路径
let filePath=__dirname+'/page'+pathname;
// 读取文件 fs 异步api
fs.readFile(filePath,(err,data)=>{
if(err){
response.statusCode=500;
response.end("文件读取失败~");
return;//防止代码继续往下执行
};
response.end(data);
})
// mime插件获取pathname的mime赋值content-type
});
server.listen(9000,()=>{
console.log('服务已经启动');
});
网页中的URL-绝对路径-相对路径
网页中使用URL的场景小结(包括但不限于)如下场景:
a标签href、link标签href、script标签src、img标签src、video audio标签、srcform中的action、AJAX请求中的URL
设置资源类型(mime类型)
媒体类型(通常称为Multipurpose Internet Mail Extensions或MIME类型)是一种标准,用来表示文档、文件或字节流的性质和格式。
mime类型结构:[type]/[subType]
例如: text/html text/css image/jpeg image/png application/json
HTTP服务可以设置响应头Content-Type
来表明响应体的MIME类型,浏览器会根据该类型决定如何处理资源
下面是常见文件对应的mime类型:
对于未知的资源类型,可以选择application/octet-stream
类型,浏览器在遇到该类型的响应时,会对响应体内容进行独立存储,也就是我们常见的下载效果
完善静态资源错误处理
请求方法不是GET的时候也会出现错误
const http=require('http');
const fs=require('fs');
const path=require('path');
const server=http.createServer((request,response)=>{
if(request.method !== 'GET'){
response.statusCode=405;
response.end('<h1>404 Not Found</h1>');
return;
}
let {pathname}=new URL(request.url,'http://127.0.0.1');
let root=__dirname+'/page';
let filePath=root+pathname;
fs.readFile(filePath,(err,data)=>{
if(err){
response.setHeader('content-type','text/html;charset=utf-8');
switch(err){
case 'ENOENT':
response.statusCode=404;
response.end('<h1>404 Not Found</h1>');
break;
case 'EPERM':
response.statusCode=403;
response.end('<h1>403 Forbidden</h1>');
break;
default:
response.statusCode=500;
response.end('<h1>500 Internal Server Error</h1>');
}
response.statusCode=500;
response.end("文件读取失败~");
return;//防止代码继续往下执行
};
// mime插件获取pathname的mime赋值content-type
// 获取文件后缀名
let ext=path.extname(filePath).slice(1);//返回的结果是.css,slice(1)从索引1开始
// 匹配对应的类型
let type=mimes[ext];
if(type){
response.setHeader('content',type+';text/html;charset=utf-8');
}else{
// 没有匹配到
response.setHeader('content-type','application/octet-stream');
};
response.end(data);
})
}).listen(9000,()=>{
console.log('服务已经启动');
});
GET和POST的区别
GET 和 POST 是 HTTP 协议请求的两种方式。区别:
- 作用:
给服务端新增数据的是post,例如创建新账户;
向服务端索要资源,加载某些东西是get - 参数位置:
GET 带参数请求是将参数缀到 URL 之后,在地址栏中输入 url 访问网站就是 GET 请求,
POST 带参数请求是将参数放到请求体中 - POST 请求
相对
GET 安全一些,因为在浏览器中参数会暴露在地址栏 - GET 请求大小有限制,一般为 2K,而 POST 请求则没有大小限制
模块化
介绍
1.模块化是一个将一个复杂的程序文件依据一定规则(规范)拆分成多个文件的过程
其中拆分出的每个文件就是一个模块
,模块的内部数据是私有的
,不过模块可以暴露内部数据以便其他模块使用
2.模块化项目:编码时是按照模块一个一个编码的,整个项目就是一个模块化的项目
3.模块化的一些好处:减少命名冲突、高复用性、高维护性
模块暴露数据两种方式:
1.module.exports=value
2.exports.name=value
使用时有几点注意:
1.module.exports可以暴露任意数据
2.不能使用exports =value 的形式暴露数据,模块内部module与exports的隐式关系exports =module.exports ={}
require返回的值是module.exports的值不是exports
exports.tiemo=tiemo相当于往{}里添加数据
node.js导入模块
在模块中使用 require 传入文件路径即可引入文件
require 使用的一些注意事项:
- 对于自己创建的模块,导入时路径建议写
相对路径
,且不能省略./
和../
- 同名文件查找顺序 .js .json .node
- js 和 json 文件导入时可以不用写后缀,c/c++编写的 node 扩展文件也可以不写后缀,但是一
般用不到 - 如果导入其他类型的文件,会以 js 文件进行处理
- 如果导入的路径是个文件夹,则会 首先 检测该文件夹下 package.json 文件中 main 属性对应的文件,
如果 main 属性不存在,或者 package.json 不存在,则会尝试导入文件夹下的index.js
和index.json
,如果还是没找到,就会报错 - 导入 node.js 内置模块时,直接 require 模块的名字即可,无需加
./
和../
,比如fs、HTTP、path
导入模块的基本流程
require 导入 自定义模块 的基本流程
- 将相对路径转为绝对路径,定位目标文件
- 缓存检测
- 读取目标文件代码
- 包裹为一个函数并执行(自执行函数)。通过 arguments.callee.toString() 查看自执行函数
- 缓存模块的值
- 返回 module.exports 的值
CommonJS模块化规范
module.exports
、exports
以及require
这些都是CommonJS模块化规范中的内容。
而Node.js是实现了CommonJS模块化规范,二者关系有点像JavaScript与ECMAScript