实现基本的注册功能
本地模拟,当输入localhost:8080/sign_up的时候,浏览器发起get请求,服务器给你响应sign_up.html
node代码:
if (path === '/sign_up' && method === 'GET') {
let string = fs.readFileSync('./sign_up.html', 'utf8')
response.statusCode = 200
response.setHeader('Content-Type', 'text/html;charset=utf-8')
response.write(string)
response.end()
}
获得用户的数据
既然是注册的需求,那么首要关注的点就是--用户的注册信息如何获得呢?
-
选择合理的数据结构存储数据是很重要的。
-
每个input的name可以使用数组存储
-
input的value应该使用hash,也就是对象来存储。
-
上述的套路会一直用下去,hash+[]的组合。
//使用jq来写
let hash = {}
let $form = $('#signUpForm')
$form.on('submit', (e) => {
e.preventDefault() //不用form表单的默认提交,而是使用我们的的ajax提交
let need = ['email', 'password', 'password_confirmation']
need.forEach((name) => {
let value = $form.find(`[name=${name}]`).val()
hash[name] = value
})
添加验证
//当出现错误提示后,若之后将信息填对了,错误信息消失。
$form.find('.errors').each((index, span) => {
$(span).text('')
})
if (hash['email'] === '') {
$form.find('[name="email"]').siblings('.error')
.text('填邮箱')
return
}
if (hash['password'] === '') {
$form.find('[name="password"]').siblings('.error')
.text('填密码')
return
}
if (hash['password_confirmationl'] === '') {
$form.find('[name="password_confirmation"]').siblings('.error')
.text('确认密码')
return
}
if (hash['password'] !== hash['password_confirmation']) {
$form.find('[name="password_confirmation"]').siblings('.error')
.text('密码不匹配')
return
}
验证完了之后,意味着浏览器收集用户数据的工作完成了,可以把hash发到服务器端了,接下来就是ajax请求了。
ajax:
$.post('/sign_up', hash)
.then((response) => {
console.log(response)
}, (request) => {
let { errors } = request.responseJSON
if (errors.email && errors.email === 'invalid') {
$form.find('[name="email"]').siblings('.error')
.text('邮箱格式错误')
//订协议
//http 协议
//前后端撕逼协议
}
})
服务器端解析formData
为了便于对From Data这段代码的理解,将它封装成一个函数让它返回Promise(因为Form Data里面的数据是一段段上传的,所以需要时间,所以是一个异步的操作,而且需要对它进行监听,所以返回Promise)
//想得到类似这种的 string == 'email=1'
function readBody(request){
return new Promise((resolve, reject)=>{
let body = []
request.on('data',(chunk)=>{
body.push(chunk)
}).on('end',()=>{
body = Buffer.concat(body).toString();
resolve(body)
})
})
}
node代码:
if (path === '/sign_up' && method === 'POST') {//sign_up注册
readBody(request).then((body) => {
let strings = body.split('&')//['email=1','password=2','possword_confirmation=3']
let hash = {}
strings.forEach((string) => {//遍历,假设第一次出现的是 'email=1'
//string == 'email=1'
let parts = string.split('=')// ['email' , '1']
let key = parts[0]
let value = parts[1]
hash[key] = decodeURIComponent(value)//hash['email'] = 1
})
let { email, password, password_confirmation } = hash
}
- 当服务器端接收到了所有的formdata数据后,是一串形如
email=1&password=2&password_confirmation=3
的字符串,所以我们考虑使用&字符分割成数组。
- 遍历数组,把数组的每个元素按照=分割,得到 [email, 1]
- 用hash+[]方法,处理成hash
错误信息的提示方法
如果有了错,需要提示用户错了,使用JSON格式。
if (email.indexOf('@') === -1) {
response.statusCode = 400
response.setHeader('Content-Type', 'application/json;charset=utf-8') //直接告诉浏览器我是json
response.write(`
{
"errors": {
"email": "invalid"
}
}
`)
}
获取json
(request) => {
let { errors } = request.responseJSON
if (errors.email && errors.email === 'invalid') {
$form.find('[name="email"]').siblings('.error')
.text('邮箱格式错误')
}
将填写的数据写入到users文件里
else{
//将文件users里面的内容赋值给users变量
var users = fs.readFileSync('./db/users','utf8')
try{
//这里之所以JSON.parse()方法会报错是因为users变量里的内容读取的是文件users里的,
//而users文件可能会被用户修改,比如改成var a=1...,而JSON.parse()方法只能将json格式的
//字符串转成对象,所以对于不确定性这里会报错
users = JSON.parse(users)
}catch(exception){
//将users变量的值替换为一个空的数组
users = []
}
users.push({email: email, password: password})
var usersString = JSON.stringify(users)
//将userString变量里的内容写入文件users里(会将原来users里面的内容替换掉)
//文件里只能写入字符串所以要将对象转为字符串存入文件
fs.writeFileSync('./db/users', usersString)
response.statusCode = 200
}
并没有使用真正意义上的数据库,只是创建一个db文件目录,里面有一个users文件做数据库,是一个空数组。
try{}catch(){}
try {
f();
} catch(e) {
// 处理错误
}
上面代码中,如果函数f执行报错,就会进行catch代码块,接着对错误进行处理。
catch代码块捕获错误之后,程序不会中断,会按照正常流程继续执行下去。
try {
throw "出错了";
} catch (e) {
console.log(111);
}console.log(222);// 111// 222
上面代码中,try代码块抛出的错误,被catch代码块捕获后,程序会继续向下执行。
如果再次点击注册按钮,在users里面就会多一个重复的对象;避免重复。
//设置一个中间变量inUse
let inUse = false;
//遍历你users这个数组,
for(let i = 0; i<users.length; i++){
//如果users里面其中有一项的email等于你传入的email
if(users[i].email === email){
//就让inUse=true
inUse = true;
//然后退出循环
break;
}
}
//如果inUse是true响应一个400请求
if(inUse){
response.statusCode = 400
response.write('email is exist')
}else{
users.push({email: email, password: password})
var usersString = JSON.stringify(users)
//将userString变量里的内容写入文件users里(会将原来users里面的内容替换掉)
//文件里只能写入字符串所以要将对象转为字符串存入文件
fs.writeFileSync('./db/users', usersString)
response.statusCode = 200
}
通过Cookie实现登录
Cookie的使用
- 如果密码和邮箱与users文件里的一致,那么点击登录按钮请求成功跳到到首页
问题1:用户可以不点登录直接访问首页的链接,并没有办法阻止用户访问首页。
问题2:登录后能不能在首页显示出你的名字/邮箱
需要在后台请求成功的时候加上一个cookie头:
response.setHeader('Set-Cookie',`sign_in_email=${email}`)
也就是说只要是set-Cookie了,之后相同域名下的所有文件的请求的请求头里面都会有一个cookie里面存储着set-Cookie里面的内容
通过Cookie实现登录后显示密码
node代码:
else if(path === '/'){
var string = fs.readFileSync('./index.html','utf8');
//let cookies = request.headers.cookie.split(';')
response.setHeader('Content-Type','text/html; charset=utf-8');
let cookies = request.headers.cookie.split('; ')
let hash = {}
for(let i =0;i<cookies.length;i++){
let parts = cookies[i].split('=')
let key = parts[0]
let value = parts[1]
hash[key]=value
}
let email = hash.sign_in_email
let users = fs.readFileSync('./db/users','utf8')
users = JSON.parse(users)
for(let i =0;i<users.length;i++){
//如果users里面的email等于你cookie的email说明登录成功
if(users[i].email === email){
//成功就将index.html里的__password__字符替换为你users文件里的password
string = string.replace('__password__',users[i].password)
}else{
//失败就替换为不知道
string = string.replace('__password__','不知道')
}
}
response.write(string)
response.end()
}
html:
<body>
你的密码是:__password__
</body>
Cookie是什么
-
Cookie 是浏览器访问服务器后,服务器传给浏览器的一段数据。
-
浏览器需要保存这段数据,不得轻易删除。
-
此后每次浏览器访问该服务器,都必须带上这段数据。
Cookie 就是这么简单,这就是 Web 开发里 Cookie 的含义。
一个具象化的例子
比如你去一个公园,需要买票它的票可以两天内无限次的出入,你每次进园都带着你的票。这个Cookie就相当于一张长期的票,一次请求就相当于一次进园,如果你想一次请求后,下次还认识你,你只需要给一个setCookie(相当于公园卖给你一张票),下次请求的时候带上你的Cookie(就相当于下次进园带上票)
Cookie特点
-
服务器通过Set-Cookie 响应头设置Cookie
-
浏览器得到Cookie后,每次请求都要带上给你Cookie
-
服务器读取Cookie就知道登录用户的信息(email)
问题
- 我在 Chrome 登录了得到 Cookie,用 Safari 访问,Safari
带上 Cookie 吗
no - Cookie 存在哪
Windows 存在 C 盘的一个文件里 - Cookie会被用户篡改吗?
可以,下节课会讲 Session 来解决这个问题,防止用户篡改 - Cookie 有效期吗?
默认有效期20分钟左右,不同浏览器策略不同
后端可以强制设置有效期,具体语法看 MDN - Cookie 遵守同源策略吗?
也有,不过跟 AJAX 的同源策略稍微有些不同。
当请求 qq.com 下的资源时,浏览器会默认带上 qq.com 对应的 Cookie,不会带上 baidu.com 对应的 Cookie
当请求 v.qq.com 下的资源时,浏览器不仅会带上 v.qq.com 的Cookie,还会带上 qq.com 的 Cookie
另外 Cookie 还可以根据路径做限制,请自行了解,这个功能用得比较少。
Cookie的两个作用
- 识别用户的身份。当用户A去访问localhost:8080的时候,服务器会给A一个独一无二的id=00A(这就是cookie),当用户A访问localhost:8080的其他网页的时候,都会带着那个独一无二的id。当B用户来访问localhost:8080的时候,服务器发现他没有任何标识,也会给他一个独一无二的id=00B,所以借助cookie服务器端就能够分清楚谁是谁了。
- 记录你的浏览历史。最常见的需求就是你去逛购物网站,你添加到购物车里面的东西过几天一定会在,而不会凭空消失了。例如A用户去taobao.com去买点东西,添加了一个热水壶、一部小米手机到购物车里面,那么服务器端可以改写你上面的cookie使之具体化「id=00A; cart=A1,A2」,表示你购物车里面买了俩东西。你过几天想起来了,去购物车里面看,热水壶、小米手机还在里面。浏览器并不会删除你存到硬盘上的cookie。
一张图总结注册登录的过程
参考:简述 Cookie 是什么
完整代码
网友评论