学习背景
上一小节我们学习了querystring和url的功能和用法,也知道了他们在实现服务端路由管理中所扮演的角色。这一节,我们就开始实现我们的路由控制,给我们之前的helloworl服务器,添加上注册,登陆,修改昵称的功能。
学习目标
使用上一章节学习的url和querystring实现路由控制,把不同请求路径映射到不用的函数或者方法上。实现我们注册,登陆,修改昵称等功能。具体路由信息如下
1、 注册一个账号
- 功能:使用用户名:zhangshan密码:123456注册用
- 请求方式:GET
- url 地址: http://localhost:8080/register?username=zhangsan&password=123456
2、登录账号并返回登录凭证
- 功能:使用刚注册的账号和密码登录获取登录凭证
- 请求方式:GET
- url 地址 http://localhost:8080/login?username=zhangsan&password=123456
3、使用登录凭证修改用户昵称
- 功能:使用上步获取的凭证修改自己的昵称
- 请求方式:GET
- url地址:http://localhost:8080/changeNickname?nickname=法外狂徒张三
实现代码
我们看看之前实现的helloworld服务器的核心代码
this.server = http.createServer(((req, res) => {
console.log('request coming')
res.writeHead(200);
res.end("hello world")
}));
this.server.listen(this.port, () => {
console.log("server start success")
})
}
这段代码就是request请求送达的时候处理的函数,如果们这时我们需要路由多个处理函数的话,就需要先用url和querystring解析出来请求的路径信息,看下面代码
// Router.js
class Router {
constructor() { // c创建一个路由模块
// 这个路由模块注册了一个名为用户信息的路由想过对象
this.userRoute = new UserRoute()
}
handle(req, res) { // 处理req和res
console.log(req.url)
const request = new url.parse(req.url)
const params = queryString.parse(request.query)
console.log("urlInfo", request)
console.log("params", params)
request.query = params
request.req = req;
switch (request.pathname) { // 根据解析出来的pathname链接到用户信息模块路由的对应参数上
case '/register': //注册
this.userRoute.register(request, res);
break
case '/login': //登陆
this.userRoute.login(request, res)
break
case '/changeNickname': //改昵称
this.userRoute.changeNickname(request, res)
break
default: // 其他路由
this.userRoute.handelOther(request, res);
break
}
}
}
// Application.js
class Application {
/**
* 创建服务
* @param port 服务运行的端口号
*/
constructor(port) {
this.port = port
this.server = null;
this.router = new Router()
}
boot() {
this.server = http.createServer(((req, res) => {
this.router.handle(req, res);
}));
this.server.listen(this.port, () => {
console.log("server start success")
})
}
}
这个代码创建了一个路由模块来解析url信息,并链接到对应的处理函数上,具体用户信息模块的处理函数如下
class UserRoute {
constructor() {
this.userList = []
this.tokenIndex = 0
}
register(req, res) {
console.log('注册')
const username = req.query.username;
const password = req.query.password;
if (!username || !password) {
res.writeHead(500, { 'Content-Type': 'text/plain;charset=utf-8' });
res.end("参数异常") // 返回前端
}
const alreadyHave = this.userList.find(s => s.username === username)
if (alreadyHave) {
res.writeHead(500, { 'Content-Type': 'text/plain;charset=utf-8' });
res.end("用户已存在") // 返回前端
}
this.userList.push({
username: username,
password: password,
nickname: '未命名',
loginToken: null,
})
res.writeHead(200, { 'Content-Type': 'text/plain;charset=utf-8' });
res.end("注册成功") // 返回前端
}
login(req, res) {
console.log('登陆')
const username = req.query.username;
const password = req.query.password;
if (!username || !password) {
res.writeHead(500, { 'Content-Type': 'text/plain;charset=utf-8' });
res.end("参数异常") // 返回前端
}
const alreadyHave = this.userList.find(s => s.username === username)
if (!alreadyHave) {
res.writeHead(500, { 'Content-Type': 'text/plain;charset=utf-8' });
res.end("用户不存在") // 返回前端
}
if (alreadyHave.password !== password) {
res.writeHead(500, { 'Content-Type': 'text/plain;charset=utf-8' });
res.end("密码错误") // 返回前端
}
res.writeHead(200, { 'Content-Type': 'text/plain;charset=utf-8' });
const token = Date.now() + '-' + this.tokenIndex
alreadyHave.token = token;
res.end(token) // 返回前端
}
changeNickname(req, res) {
console.log('改昵称')
const token = req.query.token;
const nickname = req.query.nickname;
if (!nickname || !token) {
res.writeHead(500, { 'Content-Type': 'text/plain;charset=utf-8' });
res.end("参数异常") // 返回前端
}
const user = this.userList.find(u => u.loginToken === token)
if (!user) {
res.writeHead(500, { 'Content-Type': 'text/plain;charset=utf-8' });
res.end("用户不存在") // 返回前端
}
user.nickname = nickname
res.writeHead(200, { 'Content-Type': 'text/plain;charset=utf-8' });
res.end(JSON.stringify(user)) // 返回前端
}
handelOther(req, res) {
console.log('404')
res.writeHead(404, { 'Content-Type': 'text/plain;charset=utf-8' });
res.end("您访问的地址不存在") // 返回前端
}
}
这样的话就可以链接到对应的处理函数上了,可以使用我们之前定义的几个链接地址实现注册登陆和改昵称的功能了
关键函数说明
res.writeHead(200, { ‘Content-Type’: ‘text/plain;charset=utf-8’ });
这个是给http的响应response设置响应码,200代表成功,500代表失败,404代表没有资源,“text/plain;charset=utf-8”这个是设置响应的内容类型和内容的编码,不设置这个,返回的中文会乱码。
res.end(token)
设置响应的内容
最后
通过这一章节以及上个章节《nodejs入门教程之url与querystring上(五)》的学习,我们应该掌握了url和querystring的用法,以及基于这个两个模块下来实现的服务器路由控制,实现多函数处理。最后本章节涉及的代码比较多,你可以通过访问GITHUB代码仓库下载。