1、支持用户的登录、登出
2、支持用户注册
3、支持根据输入信息查找结果
4、支持查找内容分页显示
5、支持依据用户权限返回查找信息
本项目前端使用Vue作为客户端服务器框架,后端使用Golang + BlotDB作为后端服务器框架。
此博客主要介绍项目中的前端服务器的实现。这是项目地址。
我在这个项目中负责前端的实现。由于是第一次使用Vue进行前端服务器的搭建,而且时间比较紧,因此项目只是基本完成了上述的所有基本功能,网页结构比较简陋,网页样式等额外设计基本没有。所以接下来我将着重介绍相关功能的是如何使用Vue实现的。
用户登录分两种情况:注册用户登录和游客模式登录。
注册用户登录:向服务端发送一个post请求,假如用户成功登陆,那么后端服务器将返回一个token用于后续操作的身份验证ID,前端服务器使用cookies保存此ID,并跳转至查找界面。
游客模式登录:前端服务器的cookies保存名为“guest”的特殊值,用于区分两种模式,然后跳过登陆操作直接跳转至查找界面。
// Signin.vue
post: function() {
this.$http.post("http://localhost:8080/login",
{
username:this.usr,
password:this.psw
},
{
withCredentials:true //解决跨域post
}
).then(
function(res) {
if(res.ok) {
var strContent = JSON.stringify(res.data);
var jsonContent = JSON.parse(strContent);
$cookies.set("LogInUser", jsonContent["token"]);
this.$router.push({path:"/Search"});
}
else {
alert("Error: Sign in error!");
}
},
function() {
alert("error");
});
},
guessMode: function() {
$cookies.set("LogInUser", "guest");
}
用户注册功能的提交消息到服务器的相关逻辑与用户登录功能相近,不同之处在于对后端服务器返回值的请求的处理逻辑。由于用户不一定能够成功注册,因此当新用户注册失败时,后端服务器会发送一个错误消息到前端并由前端通知用户。当注册成功后,系统默认会跳转到登录界面,进行用户的登录操作。
// Signup.vue
post: function() {
this.$http.post("http://localhost:8080/register",
{
username:this.usr,
password:this.psw
},
{
withCredentials:true
}
).then(
function(res) {
if(res.ok){
if(res.data == "Create a account\n") {
this.$router.push({path:'/'});
}
else{
alert(res.data);
}
}
},
function(res) {
alert(res.data);
});
}
这部分分为三个模块:
一是对用户输入信息的合法性进行判断:约束用户的输入格式;
二是向后端服务器请求相关查找内容:模仿swapi的查询命令,向后端服务器发送GET请求,得到后端的服务器发回来的消息后,以JSON的格式进行格式化并输出到屏幕上;
三是向后端服务器查询相关内容的总条目数:根据用户查询的类别获取条目的总数,以每页5个条目的数量分成若干页,而后前端服务器可以根据总页数以及当前用户所在的页码判断是否还有剩余内容可以查询。
// Search.vue
get: function() {
// 判断输入的合法性
var flag = /^([a-z]{1,10}((\/[0-9]*)|(\/\?page\=\d)))?$/.test(this.content);
if(!flag) {
alert("input error");
return;
}
// 向后端服务器请求相关内容
this.$http.get("http://localhost:8080/api/" + this.content).then(
function(res) {
if(res.ok) {
this.msg = JSON.stringify(res.data, null, 4);
}
}, function() {
alert("error");
});
// 向后端服务器请求相关内容的页数
if(this.content != ""){
this.getPages();
}
}
此处以向后翻页为例。
首先判断后翻一页是否超过了总页数的限制,假如超过了,那么只能显示最后一页的内容;否则,显示下一页的内容。然后更新当前用户所在的页码。
然后向后端服务器发送请求,等待后端服务器发回相关内容。当成功接收到后端服务器发回的信息后,将相关内容显示;否则,输出获取内容失败的信息。
// Search.vue
nextPage: function() {
var nowP = this.currentPage+1 <= this.pages? this.currentPage+1 : this.pages;
this.currentPage = nowP;
this.$http.get("http://localhost:8080/api/" + this.contentTag + "/?page=" + nowP).then(
function(res) {
this.msg = JSON.stringify(res.data, null, 4);
console.log("Page: ", this.currentPage, "/", this.pages);
}, function() {
alert("Error: no next page!");
});
}
这里的实现主要使用了Vue自带的拦截器的功能。每当前端服务器向后端服务器发送请求时,假如前端存储的cookies的值不为“guest”,那么证明当前正在使用的用户是注册用户,那么在报文头部加一个Authorization的键值对,用于实现jwt的token验证服务,服务器的jwt通过解析这个键值对确认用户是否有权限获取受限内容。若成功,返回相应内容;否则,返回错误信息。
// main.js
Vue.http.interceptors.push((request, next)=>{
var jwtToken = $cookies.get("LogInUser");
if(jwtToken != "guest"){
request.headers.set("Authorization", 'Bearer ' + $cookies.get("LogInUser"));
}
next((response)=>{
return response;
});
});
① 查询成功(注册用户访问/api/)
② 查询失败(游客模式访问/api/)
(1) 跨域访问功能的实现
由于浏览器为了安全而禁止了跨域访问的功能,因此在测试的时候需要输入以下命令关闭浏览器的安全功能,从而实现跨域访问。同时后端的报文还要附加上“Access-Control-Allow-Origin”和“Access-Control-Allow-Method”的键值对才能正常通信。我尝试过使用jsonp进行跨域请求,但经常出现格式错误,上网查找后推荐不使用jsonp进行跨域访问。我也尝试过修改报文头部的Origin、Host、Referer的值进行访问,但还是达不到预期的效果。后面可能会继续尝试实现在不关闭浏览器安全功能的情况下进行跨域访问的功能。
// 我测试使用的是chromium浏览器
chromium-browser --disable-web-security --user-data-dir
(2) 受限访问功能的实现
本项目使用了jwt和Token实现了注册用户的权限认证。这个功能的关键在于,前端服务器在发送请求报文的时候,需要在请求报文的头部附加上“Authronization: Bearer xxx”这一键值对。我一开始是想通过直接修改vue-resource的GET操作的header参数实现,结果发现传出去的报文实际上并没有附加上这个信息。后来通过查阅资料和实践得知,可以使用Vue的拦截器改变请求报文头部信息。拦截器的工作原理是:当前端在发送一个请求时,会先经过拦截器,然后才发送到目标地址;同样的,前端在接收到一个响应报文时,也会先经过拦截器,在调用相关处理程序。因此我们可以在拦截器设置某些条件,动态添加或删除报文的头部信息,以达到目标功能。