目录
一、创建HTTP服务
const http = require('http');
//1.创建服务对象 内部调用时接收两个实参
//request 对请求报文的封装对象
//response 对响应报文的封装
const server = http.createServer((request,response)=>{
response.end('hello')//设置响应体,并结束
});
//2.监听端口,启动服务
server.listen(9000,()=>{
console.log('9000服务已经启动')
})
注意:
1.停止服务 ctrl + c
2.代码更新问题,必须重新启动服务。nodemon可以解决这个问题,不需要频繁重新启动服务。
3.响应内容中文乱码问题
response.setHeader('content-type','text/html;charset=utf-8');
4.端口号被占用问题。停止启动服务;更换端口号
5.HTTP默认端口80,HTTPS默认端口443。HTTP开发常用端口3000,808,8090,900
如果端口被其他程序占用,可以使用资源监视器查找占用端口的程序的PID,然后使用任务管理器关闭对于的程序。
二、浏览器查看HTTP报文
1.GET请求
2.POST请求
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<form action="http://127.0.0.1:9000" method="post">
<input type="text" name="username" id="">
<input type="text" name="password" id="">
<input type="submit" id="" value="提交">
</form>
</body>
</html>
三、获取HTTP请求报文
想要获取请求数据,需要通过 request 对象
含义 | 语法 |
---|---|
请求方法 | request.method |
请求版本 | request.httpVersion |
请求路径 | request.url |
URL路径 | require('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.获取请求头
const http = require('http');
const server = http.createServer((request,response)=>{
response.setHeader('content-type','text/html;charset=utf-8');
//1.request.method
//console.log(request.method);
/*运行结果
GET
GET(favicon.ico的图标请求)
*/
//2.request.url 只包含url中的路径与查询字符串
//console.log(request.url)
/*运行结果
/home/search?name=123&pwd=233
/favicon.ico
*/
//3.request.httpVersion 获取http协议的版本号
//console.log(request.httpVersion)
/*运行结果
1.1
1.1
*/
//4.请求头 是一个对象,对象里包括请求头所有内容,每个属性名变成了小写
//console.log(request.headers);
console.log(request.headers.host);//127.0.0.1:9000
response.end('提取http报文')//设置响应体,并结束
});
server.listen(9000,()=>{
console.log('9000服务已经启动')
})
request.heaaders 请求头内容
{
host: '127.0.0.1:9000',
connection: 'keep-alive',
'cache-control': 'max-age=0',
'sec-ch-ua': '"Google Chrome";v="111", "Not(A:Brand";v="8", "Chromium";v="111"',
'sec-ch-ua-mobile': '?0',
'sec-ch-ua-platform': '"Windows"',
'upgrade-insecure-requests': '1',
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36',
accept: 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7',
'sec-fetch-site': 'none',
'sec-fetch-mode': 'navigate',
'sec-fetch-user': '?1',
'sec-fetch-dest': 'document',
'accept-encoding': 'gzip, deflate, br',
'accept-language': 'zh-CN,zh;q=0.9'
}
{
host: '127.0.0.1:9000',
connection: 'keep-alive',
'sec-ch-ua': '"Google Chrome";v="111", "Not(A:Brand";v="8", "Chromium";v="111"',
'sec-ch-ua-mobile': '?0',
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36',
'sec-ch-ua-platform': '"Windows"',
accept: 'image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8',
'sec-fetch-site': 'same-origin',
'sec-fetch-mode': 'no-cors',
'sec-fetch-dest': 'image',
referer: 'http://127.0.0.1:9000/home/search?name=123&pwd=233',
'accept-encoding': 'gzip, deflate, br',
'accept-language': 'zh-CN,zh;q=0.9'
}
2.获取请求体
const http = require('http');
const server = http.createServer((request,response)=>{
response.setHeader('content-type','text/html;charset=utf-8');
//1.声明一个变量
let body = '';
//2.绑定时间 获取可读流绑定时间
request.on('data',chunk=>{
//chunk是buffer
body += chunk.toString();
})
//3.绑定end
request.on('end',()=>{
console.log(body);//username=123&password=456
response.end('提取http请求体')//设置响应体,并结束
})
});
server.listen(9000,()=>{
console.log('9000服务已经启动')
})
3.获取请求路径和查询字符串
1. url模块
.parse
方法来将一个URL字符串转换为URL对象,.format
方法允许将一个URL对象转换为URL字符串request.url
不包含协议头和域名,但同样可以用.parse
方法解析- 第二个参数等于true时,该方法返回的URL对象中,query字段不再是一个字符串,而是经过querystring转换后的参数对象。第三个参数等于true,该方法可以正确解析不带协议头的URL,例如
//www.example.com/foo/bar
.resolve
方法可以用于拼接URL
const http = require('http');
//导入url模块
const url = require('url');
const server = http.createServer((request, response) => {
response.setHeader('content-type', 'text/html;charset=utf-8');
//解析request.url
//console.log(request.url)
let res = url.parse(request.url);
//console.log(res);
let res2 = url.parse(request.url, true); //query属性将会变成对象, query: [Object: null prototype] { keyword: '123' },
//console.log(res2);
//路径
let pathname = res.pathname;
//console.log(pathname);
/*运行结果
/search
/favicon.ico
*/
//查询字符串
let keyword = res2.query.keyword;
console.log(keyword);
/*运行结果
123
undefined
*/
response.end('提取请求路径和字符') //设置响应体,并结束
});
server.listen(9000, () => {
console.log('9000服务已经启动')
})
require('url).parse(request.url)内容
Url {
protocol: null,
slashes: null,
auth: null,
host: null,
port: null,
hostname: null,
hash: null,
search: null,
query: null,
pathname: '/',
path: '/',
href: '/'
}
Url {
protocol: null,
slashes: null,
auth: null,
host: null,
port: null,
hostname: null,
hash: null,
search: null,
query: null,
pathname: '/favicon.ico',
path: '/favicon.ico',
href: '/favicon.ico'
}
2. 实例化URL对象
- new URL(input[, base])
const http = require('http');
const server = http.createServer((request, response) => {
response.setHeader('content-type', 'text/html;charset=utf-8');
//let url = new URL('/search?code=admin&pwd=123','http://127.0.0.1:9000')
let url = new URL(request.url, 'http://127.0.0.1:9000');
//console.log(url);
console.log(url.pathname);
//输出查询字符串内容
//console.log(url.searchParams.code)// 不可行,必须用get()
console.log(url.searchParams.get('code'));
/*运行结果
/search
admin
/favicon.ico
null
*/
response.end('提取请求路径和字符2') //设置响应体,并结束
});
server.listen(9000, () => {
console.log('9000服务已经启动')
})
实例化URL对象
URL {
href: 'http://127.0.0.1:9000/search?code=admin&pwd=123',
origin: 'http://127.0.0.1:9000',
protocol: 'http:',
username: '',
password: '',
host: '127.0.0.1:9000',
hostname: '127.0.0.1',
port: '9000',
pathname: '/search',
search: '?code=admin&pwd=123',
searchParams: URLSearchParams { 'code' => 'admin', 'pwd' => '123' },
hash: ''
}
URL {
href: 'http://127.0.0.1:9000/search?code=admin&pwd=123',
origin: 'http://127.0.0.1:9000',
protocol: 'http:',
username: '',
password: '',
host: '127.0.0.1:9000',
hostname: '127.0.0.1',
port: '9000',
pathname: '/search',
search: '?code=admin&pwd=123',
searchParams: URLSearchParams { 'code' => 'admin', 'pwd' => '123' },
hash: ''
}
4.HTTP请求练习
请求类型 | 请求地址 | 响应体结果 |
---|---|---|
GET | /login | 登录页 |
GET | /reg | 注册页 |
const http = require('http')
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:500')
// console.log(method);
// console.log(pathname);
if(method === 'GET' && pathname === '/login'){
response.end('登录页')
}else if(method === 'GET' && pathname === '/reg'){
response.end('注册页')
}else{
//未改变响应状态码仍然是200
response.end('404')
}
})
server.listen(5000, () => {
console.log('5000')
})
四、设置HTTP响应报文
作用 | 语法 |
---|---|
设置响应状态码 | response.statusCode |
设置响应状态信息 | response.statusMessage |
设置响应头信息 | response.setHeader('头名', '头值') |
设置响应体 | response.write('xxxxxx') response.end('xxxxxx') |
注意:
- write可多次调用
- write,end里都存在内容,内容将会拼接成一个,所有一般情况下write里有内容,end不进行设置
- 必须有end,有且只要一个
1.设置http响应报文
const http = require('http')
const server = http.createServer((request, response) => {
response.setHeader('content-type', 'text/html;charset=utf-8');
//响应状态码
response.statusCode = 203;
//响应状态描述
response.statusMessage = 'check';
//响应头
response.setHeader('content-text', 'text/html;charset=utf-8')
response.setHeader('server', 'Node')
response.setHeader('myHeader', 'header')
//设置多个同名头
response.setHeader('headers', ['test1', 'test2'])
//响应体设置 write可多次调用
response.write('hello!')
response.write('hello!')
//必须有end(),有且仅有一个
response.end('');//如果有write,end里就不要设置了
})
server.listen(5000, () => {
console.log('5000')
})
2.HTTP响应练习
响应一个4行3列的表格,并要求表格有隔色换行的效果,且点击单元格高亮显示
1. 单独的html文件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
td {
padding: 10px 20px;
}
table,
td {
border-collapse: collapse;
}
table tr:nth-child(odd) {
background-color: skyblue;
}
table tr:nth-child(even) {
background-color: pink;
}
</style>
</head>
<body>
<table border="1">
<tr>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
</tr>
</table>
<script>
let tds = document.querySelectorAll('td');
tds.forEach(item => {
item.onclick = function () {
this.style.background = '#f0f0f0';
}
})
</script>
</body>
</html>
const http = require('http');
const fs = require('fs');
const server = http.createServer((request, response) => {
response.setHeader('content-type', 'text/html;charset=utf-8');
let html = fs.readFileSync(__dirname+'/index2.html');
response.end(html);
})
server.listen(5000, () => {
console.log('5000')
})
2.引入多个文件资源
const http = require('http');
const fs = require('fs');
const server = http.createServer((request, response) => {
//response.setHeader('content-type', 'text/html;charset=utf-8');
//let html = fs.readFileSync(__dirname+'/index2.html');
//response.end(html); 不可行
//必须根据请求url路径返回对应的结果
let {pathname} = new URL(request.url, 'http://127.0.0.1');
if(pathname ==='/'){
let html = fs.readFileSync(__dirname+'/index2.html');
response.end(html);
}else if(pathname ==='/index.css'){
let css = fs.readFileSync(__dirname+'/index.css');
response.end(css);
}else if(pathname ==='/node.png'){
let img = fs.readFileSync(__dirname+'/node.png');
response.end(img);
}else if(pathname ==='/index.js'){
let js = fs.readFileSync(__dirname+'/index.js');
response.end(js);
}else{
response.statusCode = 404;
response.end('<h3>404</h3>')
}
})
server.listen(3000, () => {
console.log('3000')
})
注意:引入多个资源文件时,必须根据需要请求的url路径做判断,响应对应文件
五、网页加载过程中向服务器发送了几个请求?
1.静态资源和动态资源
- 静态资源是指内容长时间不发生变化的资源,例如:图片、视频、css文件、js文件、html文件、字体文件。
- 动态资源是指长时间经常更新的资源,例如:百度首页、京东搜索列表页等。
2.搭建静态资源服务
/**创建一个HTTP服务,端口为6000,满足如下服务
* GET /index2.html 响应 static/index2.html内容
* GET /css/index.css 响应 static/css/index.css内容
* GET /img/node.png 响应 static/img/node.png内容
* GET /js/index.js 响应 static/js/index.js内容
*/
const http = require('http');
const fs = require('fs');
const path = require('path');
//匹配类型
let mines = {
html :'text/html',
css :'text/css',
png :'image/png',
js:'text/javascript',
json:'application/json'
}
const server = http.createServer((request, response) => {
if(request.method !== 'GET'){
response.setHeader('content-type','text/html;charset=utf-8');
response.statusCode = 405;
response.end('方法不被允许');
return;
}
//必须根据请求url路径返回对应的结果
let {pathname} = new URL(request.url, 'http://127.0.0.1');
//网站的根目录,可根据需求调整
//let root = __dirname + '/../';
let root = __dirname + '/static';
//拼接文件路径
let filename = root + pathname;
//读取文件
fs.readFile(filename,(err,data)=>{
//完善错误处理
if(err){
//判断错误代号
//console.log(err.code);
//response.setHeader('content-type','text/html;charset=utf-8');
switch(err.code){
case 'ENOENT':
response.statusCode = 404;
response.end('文件不存在');
//EPERM (操作不被允许)
case 'EPERM':
response.statusCode = 403;
response.end('无权限进行访问');
default:
response.statusCode = 500;
response.end('服务器内部错误');
}
return;
}
//设置响应文件类型,根据文件类型后缀决定
//1.获取文件后缀名
let etx = path.extname(filename).slice(1);
//console.log(etx);
//获取对应的类型
let type = mines[etx];
if(type){
//解决乱码问题
response.setHeader('content-type',type + ';charset=utf-8');
//response.setHeader('content-text',`${type};charset=utf-8`);//不生效
}else{
response.setHeader('content-type','application/octet-stream');
}
//响应文件内容
response.end(data);
})
})
server.listen(5000, () => {
console.log('5000');
})
注意:
1.HTTP服务在那个文件夹中寻找静态资源,那个人家就是静态资源目录,也称为网站根目录
六、设置资源类型(mime类型)
- 媒体类型通常被称为一种标准,用来表示文档、文件或字节流的性质和格式。
- mime类型结构 [type]/[subType],如:text/html text/css image/jpeg application/json
- HTTP设置Content-type来表明响应体的类型,浏览器会根据该类型决定如何处理资源
- 对于未知的资源可以application/octet-stream类型,浏览器会在遇到该类型时,会对响应体内容进行独立存储,也就是常见的下载效果
七、GET和POST请求的区别
- 作用:GET主要用来获取数据,POST用来提交数据
- 参数位置:GET带参数请求是将参数缀到URL中,POST带参数是将参数放到请求体中
- 安全性:POST安全性相对较高,因为浏览器中参数会暴露在地址栏中
- GET请求大小有限制,一般2K,而POST没有大小限制