创建静态服务器
web服务器一般是指网站服务器,可以向浏览器等web客户端提供文档,也可以防止网站文件让所有人浏览,还可以放置数据文件,让所有人下载。目前最主流的web服务器有:apache,nginx,IIS等
nodejs创建web服务器
这块在请求文件时会有一个文件名后缀转换的问题,通常请求的文件会有 .html .css .json .jpg .png 等格式的,可以在外面封装一个转换后缀名的方法直接调用,但是像 .json 这种格式的文件会有些不同,比如下面图片里说的,这时需要用到 url.prase() 来进行文件后缀名的获取。
- app.js
const http = require('http');
const fs = require('fs');
const path = require('path');
// 这块的这个主要是为了解决.json格式的文件后缀名转换的问题
const url = require('url');
const common = require('./module/common')
http.createServer(function (req, res) {
// 请求地址的样式 -> http://127.0.0.1:3000/index.html
// 1 获取地址
// let pathname = req.url;
let pathname = url.parse(req.url).pathname;
pathname = pathname === '/' ? '/index.html' : pathname;
// path.extname() 可以获取后缀名
let extname = path.extname(pathname);
// 2 通过fs模块读取文件
if (pathname !== '/favicon.ico') {
fs.readFile('./static' + pathname, (err, data) => {
if (err) {
res.writeHead(404, { 'Content-Type': "text/html;charset='utf-8'" });
res.end("404! 这个页面不存在");
}
let mime = common(extname);
res.writeHead(200, { 'Content-Type': ''+mime+';charset="utf-8"' });
res.end(data);
})
}
}).listen(3000);
console.log('Server running at http://127.0.0.1:3000/');
- common.js
// 3 获取请求文件的后缀名
/**
* 请求的后缀名是.html的话,响应头就是 text/html
* 请求的后缀名是.css的话,响应头就是 text/css
* 请求的后缀名是.js的话,响应头就是 text/javascript
*/
exports.getMime = function (extname) {
switch (extname) {
case '.html':
return 'text/html';
case '.css':
return 'text/css';
case '.js':
return 'text/javascript';
default:
return 'text/html';
}
}
通过从json文件中读取出来的文件后缀名
- app.js
const http = require('http');
const fs = require('fs');
const path = require('path');
// 这块的这个主要是为了解决.json格式的文件后缀名转换的问题
const url = require('url');
const common = require('./module/common');
http.createServer(function (req, res) {
// 请求地址的样式 -> http://127.0.0.1:3000/index.html
// 1 获取地址
// let pathname = req.url;
let pathname = url.parse(req.url).pathname;
pathname = pathname === '/' ? '/index.html' : pathname;
// path.extname() 可以获取后缀名
let extname = path.extname(pathname);
// 2 通过fs模块读取文件
// if (pathname !== '/favicon.ico') {
// fs.readFile('./static' + pathname, async (err, data) => {
// if (err) {
// res.writeHead(404, { 'Content-Type': "text/html;charset='utf-8'" });
// res.end("404! 这个页面不存在");
// }
// // 1 方法一 common.getFileMime()这个方法是个异步方法,所以需要用await获取
// let mime = await common.getFileMime(extname);
// res.writeHead(200, { 'Content-Type': ''+mime+';charset="utf-8"' });
// res.end(data);
// })
// }
// 除了上面的async/await之外,还有另外一种可以获取到 common.getFileMime 异步方法里面的数据
if (pathname !== '/favicon.ico') {
fs.readFile('./static' + pathname, (err, data) => {
if (err) {
res.writeHead(404, { 'Content-Type': "text/html;charset='utf-8'" });
res.end("404! 这个页面不存在");
}
let mime = common.getFileMime(extname);
res.writeHead(200, { 'Content-Type': ''+mime+';charset="utf-8"' });
res.end(data);
})
}
}).listen(3000);
console.log('Server running at http://127.0.0.1:3000/');
- common.js
// 3 获取请求文件的后缀名
/**
* 请求的后缀名是.html的话,响应头就是 text/html
* 请求的后缀名是.css的话,响应头就是 text/css
* 请求的后缀名是.js的话,响应头就是 text/javascript
*/
const fs = require('fs');
// 这块的这个是后缀名是直接写死的,也就只有固定的几个
// exports.getMime = function (extname) {
// switch (extname) {
// case '.html':
// return 'text/html';
// case '.css':
// return 'text/css';
// case '.js':
// return 'text/javascript';
// default:
// return 'text/html';
// }
// }
// 这块是从json文件中读取出来的文件后缀名
// exports.getFileMime = function (extname) {
// return new Promise((resolve, reject) => {
// fs.readFile('./../data/mime.json', (err, json) => {
// if (err) {
// reject(err);
// return;
// }
// let mimeObj = JSON.parse(data.toString());
// // 上面这块是异步方法,不能直接返回,可以放在promise中
// resolve(mimeObj[extname])
// })
// })
// }
// 还有下面这种方法和上面的这个效果一样
exports.getFileMime = function (extname) {
// 下面这个是同步方法,如果nodejs中提供了这个方法的话就可以用了
var data = fs.readFileSync('./data/mime.json'); // 同步方法读取内容(读取完后才会向下执行)
let mimeObj = JSON.parse(data.toString());
return mimeObj[extname];
}
- data/mime.json
{
".html":"text/html",
".css":"text/css",
".js":"text/javascript",
".zip":"application/zip",
".json":"application/json"
}
这样的话也是可以的
主要思路:
在浏览器中访问某个url的时候,如:http://127.0.0.1:3000/index.html
- 先获取到浏览器中输入这个地址
- 获取到地址之后,通过fs模块读取文件
readFile
这个方法,去static目录里面去读取一下访问的文件 - 读取到文件之后就可以返回读取到的内容了,返回的时候要注意一下类型(就是通过mime来找对应的类型)
对静态web服务进行封装
将之前module/common.js改为module/routes.js
- module/routes.js
const fs = require('fs');
const path = require('path');
const url = require('url');
let getFileMime = function (extname) {
var data = fs.readFileSync('./data/mime.json'); // 同步方法读取内容(读取完后才会向下执行)
let mimeObj = JSON.parse(data.toString());
return mimeObj[extname];
}
exports.static = function (req, res, staticPath) {
// 1 获取地址
let pathname = url.parse(req.url).pathname;
pathname = pathname === '/' ? '/index.html' : pathname;
// path.extname() 可以获取后缀名
let extname = path.extname(pathname);
if (pathname !== '/favicon.ico') {
fs.readFile('./' + staticPath + pathname, (err, data) => {
if (err) {
res.writeHead(404, {
'Content-Type': "text/html;charset='utf-8'"
});
res.end("404! 这个页面不存在");
}
let mime = getFileMime(extname);
res.writeHead(200, {
'Content-Type': '' + mime + ';charset="utf-8"'
});
res.end(data);
})
}
}
- app.js
const http = require('http');
const routes = require('./module/routes');
http.createServer(function (req, res) {
// 创建静态web服务
routes.static(req, res, 'static')
}).listen(3000);
console.log('Server running at http://127.0.0.1:3000/');
这样封装后照样可以访问
路由
针对不同的请求URL,处理不同的业务逻辑
- routes.js
const fs = require('fs');
const path = require('path');
const url = require('url');
let getFileMime = function (extname) {
var data = fs.readFileSync('./data/mime.json'); // 同步方法读取内容(读取完后才会向下执行)
let mimeObj = JSON.parse(data.toString());
return mimeObj[extname];
}
exports.static = function (req, res, staticPath) {
// 1 获取地址
let pathname = url.parse(req.url).pathname;
pathname = pathname === '/' ? '/index.html' : pathname;
// path.extname() 可以获取后缀名
let extname = path.extname(pathname);
if (pathname !== '/favicon.ico') {
try {
let data = fs.readFileSync('./' + staticPath + pathname);
if (data) {
// 如果不是err的话,说明static目录中有需要的文件,有的话就读取出来
// 没有的话就不做任何操作
let mime = getFileMime(extname);
res.writeHead(200, {
'Content-Type': '' + mime + ';charset="utf-8"'
});
res.end(data);
}
} catch (error) {
console.log(error);
}
}
}
- app.js
const http = require('http');
const routes = require('./module/routes');
const url = require('url');
http.createServer(function (req, res) {
// 创建静态web服务
// 先走这里,如果能匹配的到的话,就会直接调用routes里面的那个res.end(data),不会继续向下匹配了
routes.static(req, res, 'static');
// 路由
let pathname = url.parse(req.url).pathname;
// 配合路由的话,当你加载不到一个页面的时候你需要继续向下匹配,看下面的路由能不能匹配到,如果不行的话可以返回404
if(pathname === '/login'){
res.writeHead(200, { 'Content-Type': 'text/html;charset="utf-8"' });
res.end("login");
}else if(pathname === '/register'){
res.writeHead(200, { 'Content-Type': 'text/html;charset="utf-8"' });
res.end("执行注册");
}else if(pathname === '/admin'){
res.writeHead(200, { 'Content-Type': 'text/html;charset="utf-8"' });
res.end("处理后的业务逻辑");
}else{
res.writeHead(404, { 'Content-Type': 'text/html;charset="utf-8"' });
res.end("页面不存在");
}
}).listen(3000);
console.log('Server running at http://127.0.0.1:3000/');
ejs
- install
npm install ejs
- ejs 的用法
ejs.renderFile(filename, data, options, (err, data) => {
// str => rendered html string
})
- views/login.ejs
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<h2>这是一个哈哈哈</h2>
<h3><%=msg%></h3>
<ul>
<%for(var i = 0; i < list.length; i++){%>
<li>
<%=list[i].name%>
</li>
<%}%>
</ul>
</body>
</html>
- app.js
const http = require('http');
const routes = require('./module/routes');
const url = require('url');
const ejs = require('ejs');
http.createServer(function (req, res) {
// 创建静态web服务
// 先走这里,如果能匹配的到的话,就会直接调用routes里面的那个res.end(data),不会继续向下匹配了
routes.static(req, res, 'static');
// 路由
let pathname = url.parse(req.url).pathname;
// 配合路由的话,当你加载不到一个页面的时候你需要继续向下匹配,看下面的路由能不能匹配到,如果不行的话可以返回404
if (pathname === '/login') {
let msg = 'database data';
let list = [{
name: '111'
},
{
name: '222'
},
{
name: '333'
}
]
// 这块加载的文件是动态的,和在static中写的是不一样的
ejs.renderFile('./views/login.ejs', {
msg: msg,
list: list
}, (err, data) => {
res.writeHead(200, {
'Content-Type': 'text/html;charset="utf-8"'
});
res.end(data);
})
} else if (pathname === '/register') {
res.writeHead(200, {
'Content-Type': 'text/html;charset="utf-8"'
});
res.end("执行注册");
} else if (pathname === '/admin') {
res.writeHead(200, {
'Content-Type': 'text/html;charset="utf-8"'
});
res.end("处理后的业务逻辑");
} else {
res.writeHead(404, {
'Content-Type': 'text/html;charset="utf-8"'
});
res.end("页面不存在");
}
}).listen(3000);
console.log('Server running at http://127.0.0.1:3000/');
get / post
- views/form.js
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<form action="/doLogin" method="post">
用户名:<input type="text" name="username" />
密 码:<input type="text" name="password" />
<input type="submit" value="提交">
</form>
</body>
</html>
- app.js
const http = require('http');
const routes = require('./module/routes');
const url = require('url');
const ejs = require('ejs');
http.createServer(function (req, res) {
// 创建静态web服务
// 先走这里,如果能匹配的到的话,就会直接调用routes里面的那个res.end(data),不会继续向下匹配了
// routes.static(req, res, 'static');
// 路由
let pathname = url.parse(req.url).pathname;
// 获取请求类型
console.log(req.method);
// 配合路由的话,当你加载不到一个页面的时候你需要继续向下匹配,看下面的路由能不能匹配到,如果不行的话可以返回404
if (pathname === '/news') {
// get请求演示
var query = url.parse(req.url, true).query;
console.log(query);
res.writeHead(200, {
'Content-Type': 'text/html;charset="utf-8"'
});
res.end("get传值获取成功");
} else if (pathname === '/login') {
// post请求演示
ejs.renderFile("./views/form.ejs", {}, (err, data) => {
res.writeHead(200, {
'Content-Type': 'text/html;charset="utf-8"'
});
res.end(data);
})
} else if (pathname === '/doLogin') {
// 获取post传值
let postData = '';
req.on('data', (chunk)=>{
postData += chunk;
})
req.on('end', ()=>{
console.log(postData);
res.end(postData);
})
} else {
res.writeHead(404, {
'Content-Type': 'text/html;charset="utf-8"'
});
res.end("页面不存在");
}
}).listen(3000);
console.log('Server running at http://127.0.0.1:3000/');
这块demo练习的就是一个简单的登录页面,获取这个登录页面是get请求,在登录页面输入对应的username和password之后点击提交是post请求,点击完提交之后获取到输入的username和password的数据也是post请求