nodejs-02
服务器的优化
- 对图片、json等数据的文件头进行修改(用到mime.json文件)
- 使用Nodejs提供的同步读取文件方法来对文件进行读取操作
原先写入Content-Type的代码: 类型少,无法识别json、js、png等格式
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'
}
}
mime.json文件:(部分) 种类齐全,通过fs模块读取,并且使用JSON.parse方法转换成对象,然后使用[键]获取到对应的Content-Type
{ ".323":"text/h323" ,
".3gp":"video/3gpp" ,
".aab":"application/x-authoware-bin" ,
".aam":"application/x-authoware-map" ,
".aas":"application/x-authoware-seg" ,
".acx":"application/internet-property-stream" ,
".ai":"application/postscript" ,
".aif":"audio/x-aiff" ,
}
// 因为文件操作是异步的,所以可以让下面的方法return一个Promise
exports.getFileMime = function(extname){
return new Promise((resolve, reject)=>{
fs.readFile('./data/mime.json', (err, data)=>{
if(err){
reject(err)
return
}
// 对读取进来的json文件parse
let mime = JSON.parse(data.toString())
// 查找相对应的Content-Type
resolve(mime[extname])
})
})
}
app.js中写入contenttype:
// 使用了async和await,因为前面exports的方法是异步方法
fs.readFile(`./static${pathName}`, async (err, data) => {
if (err) {
res.writeHead(404, { 'Content-Type': 'text/html;charset="utf-8"' })
res.end('404')
}
//过滤文件,使不同的静态文件都可以以正确的文件头渲染
let mime = await common.getFileMime(extName)
res.writeHead(200, { 'Content-Type': ''+mime+';charset="utf-8"' })
res.end(data)
})
另外还可以使用同步的方法来读取mime.json文件:
exports.getFileMimeSync = function(extname){
// fs模块中提供的同步读取文件方法
let data = fs.readFileSync('./data/mime.json')
let mime = JSON.parse(data.toString())
return mime[extname]
}
这样就可以不使用async和await读取到文件
fs.readFile(`./static${pathName}`, (err, data) => {
if (err) {
res.writeHead(404, { 'Content-Type': 'text/html;charset="utf-8"' })
res.end('404')
}
//过滤文件,使不同的静态文件都可以以正确的文件头渲染
// nodejs提供的同步读取文件的方法,这里可以不使用async和await就可以获取到文件
let mime = common.getFileMimeSync(extName)
res.writeHead(200, { 'Content-Type': ''+mime+';charset="utf-8"' })
res.end(data)
})
web服务和静态路由
路由
路由(Routing)是由一个URL和一个特定的http方法(get post)组成的,涉及到应用如何响应客户端对某个网站节点的访问,通俗来说路由指的就是针对不同请求的url,处理不同的业务逻辑
比如说当我们需要访问登陆页面,我们可以访问 http://127.0.0.1:8111/login (这和http://127.0.0.1:8111/login.html是不一样的)
先把之前编写的创建服务器的代码进行封装
在routes.js中:
// 把创建服务器的相关操作封装好,减少app.js的代码量
exports.static = function (req, res, staticPath) {
// 1. 获取地址
let pathName = url.parse(req.url).pathname
// 判断url是否为/ 如果是的话就把'/index.html'赋给pathName,强行跳转index
pathName = pathName === '/' ? '/index.html' : pathName
// 通过path模块获取url的后缀名
let extName = path.extname(pathName)
// 2. 通过fs模块读取文件,
if (pathName !== '/favicon.ico') { // 先过滤掉其他无关的url
// 把获取到的url拼接到文件读取流的参数中,读取HTML文件
try {
// 同步读取
let data = fs.readFileSync(`./${staticPath}${pathName}`)
//过滤文件,使不同的静态文件都可以以正确的文件头渲染
if (data) {
let mime = getFileMimeSync(extName)
res.writeHead(200, { 'Content-Type': '' + mime + ';charset="utf-8"' })
res.end(data)
}
} catch (error) {}
}
}
然后在app.js中引用这个模块,并且:
const routes = require('./module/routes')
routes.static(req, res, 'static')
下面是路由的实现方式
-
首先需要对req.url进行解析
let pathname = url.parse(req.url).pathname
-
然后对不同的路径进行判断
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('register') } else if (pathname === '/admin') { res.writeHead(200, { 'Content-Type': 'text/html;charset="utf-8"' }) res.end('admin') } else { res.writeHead(200, { 'Content-Type': 'text/html;charset="utf-8"' }) res.end('404') }
此处需要注意的是,当我们封装好的创建服务器代码中如果包含异步的方法,可能会导致首页无法加载完成,所以可以使用同步的方法来对static路径中的资源进行读取,确保读取完成资源后再进行路由判断
模板引擎
本课程使用ejs模板引擎
使用npm命令安装ejs模板引擎,安装完成后使用ejs编写页面
在app.js中有如下两条数据
let msg = '我是模拟数据'
let list = [
{'title': '1'},
{'title': '2'},
{'title': '3'},
{'title': '4'}
]
使用模板引擎把它们渲染到页面上:
if (pathname === '/login') {
/**
* 要渲染的模板
* 要渲染进去的参数(对象
* 回调函数
*/
ejs.renderFile('./views/login.ejs', {msg, list}, (err, data) => {
res.writeHead(200, {'Content-Type': 'text/html;charset="utf-8"'})
res.end(data)
})
}
在login.ejs中:
<body>
<h2>ejs</h2>
<h3><%= msg %></h3>
<br>
<ul>
<%for(var i=0;i<list.length;i++){%>
<li><%=list[i].title%></li>
<%}%>
</ul>
</body>
这样就可以把数据动态渲染在页面上
GET&&POST...
在客户端和无武器之间进行请求响应时,用到最多的是get和post
-
get用于从制定的资源请求数据
-
post用于向指定的资源提交要被处理的数据
使用get来获取url中的相关信息(使用url模块中的parse方法,并且获取其中的query):
const url = require('url')
if (pathname === '/news'){
let query = url.parse(req.url, true).query
// 可以通过req.method来获取请求类型
console.log(req.method)
console.log(query)
res.writeHead(200, {'Content-Type': 'text/html;charset="utf-8"'})
res.end('query')
}
使用post请求提交数据:
模板中的表单
<body>
<form action="/doLogin" method="post">
<input type="text" name="username"/>
<br>
<input type="password" name="password"/>
<br>
<input type="submit" value="submit">
</form>
</body>
访问的login路由
if (pathname === '/login') {
//post演示,渲染模板
ejs.renderFile('./views/form.ejs', {}, (err, data) => {
res.writeHead(200, {'Content-Type': 'text/html;charset="utf-8"'})
res.end(data)
})
}
访问的doLogin路由(原生js获取post数据):
if (pathname === '/doLogin') {
let postData = ''
// on读取数据是通过流方式来读取,所以需要拼接,chunk是读取的片段
req.on('data', chunk=>{
postData += chunk
})
req.on('end', ()=>{
console.log(postData)
res.end(postData)
})
res.writeHead(200, {'Content-Type': 'text/html;charset="utf-8"'})
}
输出结果:
E:\nodejs\demo12>node app.js
http://127.0.0.1:8111/
username=2017123456&password=123123
网友评论