一、实验内容
本学期web实验课我做了两方面的内容,一方面是有机农场管理系统的继续完善,另一方面是系统模块功能的展,实现利用Cookie的登录注册功能。
仔细研究了去年的web项目,在有机农场管理系统的基础上更改了原系统的CSS和HTML等,使界面更加美观。又在原系统基础上扩展了登录功能,实现了登录注册功能。并且利用了cookie识别用户的身份。
二、实验目的
掌握常见网页设计工具的使用,熟悉web站点的开发工具环境和使用方法。掌握建立一个web的基本过程,掌握网站设计的基本技术与技巧。
根据要求,给出网页设计方案,可以按照要求,利用合适的图文素材设计符合要求的网页设计作品。注意版面布局、色彩搭配等,网站链接自然,顺畅方便。了解和熟悉网页式设计的基础知识和实现技巧。
熟练掌握html,CSS,JavaScript,node.js等的操作和使用。增强动手实践能力,进一步加强自身综合素质。逐渐培养做一个完整项目的能力。
三、实验原理
1、什么是Cookie
Cookie 是服务器保存在浏览器的一小段文本信息。浏览器每次向服务器发出请求,就会自动附上这段信息。
2、Cookie的作用
(1)Cookie 主要用来分辨两个请求是否来自同一个浏览器
(2)用来保存一些状态信息,例如:
a.对话(session)管理:保存登录、购物车等需要记录的信息。
b.个性化:保存用户的偏好,比如网页的字体大小、背景色等等。
c.追踪:记录和分析用户行为。
不推荐使用Cookie作为客户端存储,原因:
a.它的容量很小(4KB)。
b.缺乏数据操作接口。
c.而且会影响性能。
(3)使用Cookie一般有两个作用。第一个作用是识别用户身份,第二个作用是记录历史。
3、Cookie的组成
Cookie 包含以下几方面的信息:
a. Cookie 的名字。
b. Cookie 的值。(真正的数据写在这里面)(a、b两点是键值对 )
c. 到期时间。
d. 所属域名。(默认是当前域名)
e. 生效的路径。(默认是当前网址)(c/d/e是cookie的属性)
4、Cookies作用范围
浏览器的同源政策规定,两个网址只要域名相同和端口相同,就可以共享 Cookie。注意,这里不要求协议相同。也就是说,http://example.com设置的 Cookie,可以被https://example.com读取。
同源限制方面内容可以参考网页:
https://wangdoc.com/javascript/bom/same-origin.html
四、实验过程
1、HTTP 协议中的Cookie
HTTP 回应:Cookie 的生成(服务器端生成cookies)
服务器如果希望在浏览器保存 Cookie,就要在 HTTP 回应的头信息里面,放置一个Set-Cookie字段:
Set-Cookie:foo=bar
上面的代码会在浏览器保存一个名为foo的 Cookie,它的值为bar。
设置的格式为:<键(名)>=<值>。
HTTP 回应可以包含多个Set-Cookie字段,即在浏览器生成多个 Cookie。下面是一个例子:
HTTP/1.0 200 OK
Content-type: text/html
Set-Cookie: yummy_cookie=choco
Set-Cookie: tasty_cookie=strawberry
[page content]
除了 Cookie 的值,Set-Cookie字段还可以附加 Cookie 的属性。一个Set-Cookie字段里面,可以同时包括多个属性,没有次序的要求。下面是设置一个Cookie的例子:除了名与它的值,还包含Domain属性Secure属性和HttpPnly属性:
Set-Cookie:<cookie-name>=<cookie-value>;
Domain=<domain-value>;Secure; HttpOnly
除了键=值来设置cookie的名字和值之外,还可以设置属性。
a. Expires,Max-Age用来设置cookie持续时间。
b. Domain,Path设置发送http请求时那些域名和路径需要附带这个Cookie。
c. Secure属性指定浏览器只有在加密协议 HTTPS 下才能发送。
d. HttpOnly属性指定该 Cookie 无法通过 JavaScript 脚本拿到。
具体用法可以参考网上的很多博客,这里不再赘述。
HTTP 请求:Cookie 的发送(浏览器发送Cookie)
浏览器向服务器发送 HTTP 请求时,每个请求都会带上相应的 Cookie。也就是说,把服务器早前保存在浏览器的这段信息,再发回服务器。这时要使用 HTTP 头信息的Cookie字段。
Cookie: foo=bar
上面代码会向服务器发送名为foo的 Cookie,值为bar。
Cookie字段可以包含多个 Cookie,使用分号(;)分隔。
Cookie: name=value; name2=value2; name3=value3
下面是一个Http请求的例子。
GET /sample_page.html HTTP/1.1
Host: www.example.org
Cookie: yummy_cookie=choco; tasty_cookie=strawberry
服务器收到浏览器发来的 Cookie 时,有两点是无法知道的(因为这些Cookie的属性只保存在浏览器上)。
a.Cookie 的各种属性,比如何时过期。
b.哪个域名设置的 Cookie,到底是一级域名设的,还是某一个二级域名设的。
2、document.cookie读写当前网页的Cookie
读Cookie
读取的时候,它会返回当前网页的所有 Cookie,前提是该 Cookie 不能有HTTPOnly属性。
document.cookie // "foo=bar;baz=bar"
写Coookie
document.cookie属性是可写的,可以通过它为当前网站添加 Cookie。等号两边不能有空格
document.cookie = 'fontSize=14';
但是,document.cookie一次只能写入一个 Cookie,而且写入并不是覆盖,而是添加。
document.cookie = 'test1=hello';
document.cookie = 'test2=world';
document.cookie
// test1=hello;test2=world
写入 Cookie 的时候,可以一起写入 Cookie 的属性。
document.cookie = "foo=bar; expires=Fri, 31 Dec 2020 23:59:59 GMT";
各个属性的写入注意点如下:
a. path属性必须为绝对路径,默认为当前路径。
b. domain属性值必须是当前发送 Cookie 的域名的一部分。比如,当前域名是example.com,就不能将其设为foo.com。该属性默认为当前的一级域名(不含二级域名)。
c. max-age属性的值为秒数。
d. expires属性的值为 UTC 格式,可以使用 Date.prototype.toUTCString ()进行日期格式转换。
document. cookie写入 Cookie 的例子如下。
Document.cookie = 'fontSize=14; '
+ 'expires=' + someDate.toGMTString() + '; '
+ 'path=/subdirectory; '
+ 'domain=*.example.com';
Cookie 的属性一旦设置完成,就没有办法读取这些属性的值。
3、Cookie 的删除
删除一个现存 Cookie 的唯一方法,是设置它的expires属性为一个过去的日期。
document.cookie = 'fontSize=;expires=Thu, 01-Jan-1970 00:00:01 GMT';
上面代码中,名为fontSize的 Cookie 的值为空,过期时间设为1970年1月1月零点,就等同于删除了这个 Cookie。
五、实验内容
1、利用cookie实现登录注册
这个项目是一个cookie的简单例子, 有以下结构:
index.html: 首页
sign_in.html: 登录页面
sign_up.html: 注册页面
server.js: 服务器
db/users: 模拟数据库, 实质上是一个数组, 每个数组项是一个对象, 表示一个用户。
程序运行需要使用node作为服务器。node server.js 8888。在浏览器中输入localhost:8888, 就可以看到index.html页面。
在地址栏输入localhost:8888/sign_up, 会进入注册页面, 即sign_up.html。输入要注册的邮箱即密码, 若已注册过则显示已注册, 没有注册则会注册成功。
在地址栏输入localhost:8888/sign_in, 得到登录页面sign_in.html, 输入刚才注册的账号, 会进入首页index.html, 还会显示个人账户信息。
当输入localhost:8888直接进入index.html页面时, 没有用户登录. 此时就没有设置cookie, 首页不会显示用户的cookie。
若通过用户登录进入首页, 则会设置cookie. 首页也会显示账户。
(1)Cookie在注册登录时的作用过程
注册:注册时把账号密码写入数据库。
登录:第一次登录时服务器给浏览器发送Cookie。
后台的登录路由代码(nodejs):
else if (path === '/sign_in' && method === 'POST') {
readBody(request).then((body) => {
let strings=body.split('&')
let hash = {}
strings.forEach((string) => {
let parts = string.split('=')
let key = parts[0]
let value = parts[1]
hash[key] = decodeURIComponent(value)
})
let {
email,
password
} = hash
var users = fs.readFileSync('./db/users', 'utf8')
try {
users = JSON.parse(users) // []
} catch (exception) {
users = []
}
let found
for (let i = 0; i < users.length; i++) {
if (users[i].email === email && users[i].password === password) {
found = true
break
}
}
if (found) {//关键在这里,验证成功,设置登录Cookie为登录的邮箱,并放在响应里发给浏览器
response.setHeader('Set-Cookie', `sign_in_email=${email}`)
response.statusCode = 200
} else {
response.statusCode = 401
}
response.end()
})
}
在登录成功的一瞬间,需要后台设置一个Cookie,记录一下登陆的用户id(这里用邮箱表示,代码在上面),然后发响应给浏览器。
发现跳转到主页的请求头中包含cookie字段(以后访问这个域名都会带着这个Cookie)所以,这说明了:
如果服务器给了浏览器一个setcookie的响应头,那么这个浏览器以后所有的请求,只要是相同的源(即就是上次给我发送Cookie的那个域名,域名和端口相同),那就么就会把当时服务器发给这个浏览器的Cookie带着。
以后,浏览器一旦访问这个路径,浏览器就会附上这段 Cookie 发送给服务器
即:第一次请求,服务器为浏览器设置Cookie.下次请求,浏览器带上Cookie,发送给服务器。
第一次登录的时候,服务器给浏览器的响应设置一个Cookie,set-cookies:user_email=1@mtt.com,然后当浏览器下次进行请求的时候,发现Cookie中有名为User_email的Cookie,而且我发送请求的域名还是上次发给我带Cookie的响应的那个域名。那么就无需再次登录了。
相当于服务器给浏览器发了进入门票,下次或下下次浏览器在进入服务器的时候给服务器看票就可以了。
Cookie的作用过程:
假设用户访问网址www.example.com,服务器在浏览器写入一个 Cookie。这个 Cookie
就会包含www.example.com这个域名(d),以及根路径/(e)。这意味着,这个 Cookie 对该域名的根路径和它的所有子路径都有效。如果路径设为/forums,那么这个 Cookie 只有在访问www.example.com/forums及其子路径时才有效。
以后,浏览器一旦访问这个路径,浏览器就会附上这段 Cookie 发送给服务器。
- 后台读取Cookie保留登录状态与删除Cookie退出登录状态
首页代码:
<body>
<h1>我是首页</h1>
<div class="">
<a href="./sign_up">注册</a>
<a href="./sign_in">登录</a>
</div>
<h1>你的状态是:__status__</h1>
<h1>你的邮箱账号是:__email__</h1>
<h1>你的密码是:__password__</h1>
<a href="javascript:;" id="logOffBtn">退出登录(删除cookie)</a>
</body>
<script>
logOffBtn.addEventListener("click", () => {
// 删除一个现存 Cookie 的唯一方法,是设置它的expires属性为一个过去的日期。
document.cookie = 'sign_in_email=;expires=Thu, 01-Jan-1970 00:00:01 GMT'
window.location = "/"
})
</script>
后台路由代码:
if (path === '/') {
response.statusCode = 200
let string = fs.readFileSync('./index.html')
string = string.toString();
var users = fs.readFileSync('./db/users', 'utf8')
users = JSON.parse(users)//转化为user对象数组
console.log(users);
let cookies = request.headers.cookie || ''//['email=111', 'asdasd=111']
cookies = cookies.split("; ")
let hash={}
cookies.forEach((string)=>{
let parts = string.split("=")
let key = parts[0]
let value = parts[1]
hash[key] = value;
})
let eamil = hash.sign_in_email
let foundedUser
users.forEach((userObj)=>{
if(userObj.email===eamil){
foundedUser = userObj;
}
}
)
console.log(foundedUser);
if(foundedUser){
string = string.replace('__status__', '已登录')
string = string.replace('__email__', foundedUser.email)
string = string.replace('__password__', foundedUser.password)
}else{
string = string.replace('__status__', '未登录,请去登录')
string = string.replace('__email__', '没')
string = string.replace('__password__', '没')
}
response.setHeader('Content-Type', 'text/html;charset=utf-8')
response.write(string)
response.end()
}
测试时,在没有Cookie的时候,首页的状态:
测试时,登录之后,后台根据Cookie查询数据库,将用户名与密码传到前台的首页上:
退出登录将删除Cookie并刷新页面,重新回到未登录的状态
其他界面截图:
(3)Cookie在登录的时候的特点
a. 第一次登录的时候,服务器通过 Set-Cookie 响应头设置 Cookie,然后以响应的形式发给浏览器
b. 浏览器得到 响应中Cookie 之后,之后每次请求这个域名都要带上这个 Cookie
c. 之后服务器读取当时自己设置的 Cookie 就知道登录用户的信息(email)
(4)需要注意的细节问题
A.在Chrome登录了得到Cookie,用Safari访问,Safari会带上Cookie
- 前后端都要进行表单验证.前后端都要验证邮箱格式是否正确,账号密码格式是否正确,两次提交的密码是否相同等。因为黑客可以绕过前端的js验证流程,例如黑客可以直接使用curl 进行请求的发送,直接与后台服务器进行交互。所以后台也需要进行表单验证。
- 在谷歌浏览器开发者模式下的application->Cookie中可以手动修改Cookie,修改之后,下次发送请求时,附带的就是修改后的Cookie。
JS中也有可以操作cookie的api( 假如换成别的用户的账号,那么还可以登录成功的话,就会存在风险问题.Session 来解决这个问题,防止用户篡改)。
后端可以强制设置不允许修改Cookie,只要将Cookie的属性设置为Httponly即可(还可以手动改,但是JS改不了,也无法获取),具体语法看 MDN。
D.Cookie默认有效期20分钟左右,不同浏览器策略不同(如果浏览器一直开着,那么Cookie不会被删除。如果关闭浏览器,那么浏览器为了安全考虑,20分钟左右后可能会删除Cookie.这也取决于服务器如何设置Cookie的有效期)。后端可以强制设置有效期。
2、有机农场管理系统的页面完善
HTML和CSS更改页面:
登陆注册页面的最终实现效果
进入有机农场管理系统后的实现效果:
项目依赖于: Node.js,必须安装node.js才能运行此项目
启动服务器: node ./bin/www
打开前台界面: http://127.0.0.1:3000
静态网站位于: FarmManger/public
项目使用框架: Express
但是原项目代码里设置的是FarmManger/public/index.html,项目中却没有index.html。我将它改成了自己的文件路径和login.html。
运行截图;
部分更新代码截图:
server.js:
var http = require('http')
var fs = require('fs')
var url = require('url')
var port = process.argv[2]
var sessions ={}
if (!port) {
console.log('?\nnode server.js 8888 ')
process.exit(1)
}
var server = http.createServer(function (request, response) {
var parsedUrl = url.parse(request.url, true)
var pathWithQuery = request.url
var queryString = ''
if (pathWithQuery.indexOf('?') >= 0) {
queryString = pathWithQuery.substring(pathWithQuery.indexOf('?'))
}
var path = parsedUrl.pathname
var query = parsedUrl.query
var method = request.method
// 这里开始写注册登录的路由
console.log('含查询字符串的路径\n' + pathWithQuery)
if (path === '/') {
response.statusCode = 200
let string = fs.readFileSync('./index.html')
string = string.toString();
var users = fs.readFileSync('./db/users', 'utf8')
users = JSON.parse(users)//转化为user对象数组
console.log(users);//打印在服务器端的控制台
let cookies = request.headers.cookie || ''//'sessionID=xxx', 'asdasd=111'
console.log("cookies:"+cookies);
cookies = cookies.split("; ")
let hash={}
cookies.forEach((string)=>{
let parts = string.split("=")
let key = parts[0]
let value = parts[1]
hash[key] = value;
})
let eamil
let mySession = sessions[hash.sessionID];
if(mySession){
console.log("mySession.sign_in_email:::"+mySession.sign_in_email)
eamil = sessions[hash.sessionID].sign_in_email
}
let foundedUser
users.forEach((userObj)=>{
if(userObj.email===eamil){
foundedUser = userObj;
}
})
console.log("foundedUser"+foundedUser);
if(foundedUser){
string = string.replace('__status__', '已登录')
string = string.replace('__email__', foundedUser.email)
string = string.replace('__password__', foundedUser.password)
}else{
string = string.replace('__status__', '未登录,请去登录')
string = string.replace('__email__', '没')
string = string.replace('__password__', '没')
}
response.setHeader('Content-Type', 'text/html;charset=utf-8')
response.write(string)
response.end()
} else if (path === '/sign_up' && method === 'GET') { //这个路由只限进入sign_up这个页面,所以只需要用get,不附带数据,下面提交表单采用post
response.statusCode = 200
let string = fs.readFileSync('./sign_up.html')
response.setHeader('Content-Type', 'text/html;charset=utf-8')
response.write(string)
response.end()
} else if (path === '/sign_up' && method === 'POST') { //提交注册表单的路由
readBody(request).then((body) => { //使用封装的读取body的函数,成功后参数为body,因为这里是异步事件,所以需要使用promise封装
let message = body.split('&') //['email=1','password=2','repassword=3']
let hash = {}
message.forEach(element => {
let parts = element.split('=')
let key = parts[0]
let value = parts[1]
hash[key] = decodeURIComponent(value)
});
console.log(hash);
let {
email,
password,
repassword
} = hash //es6语法
if (email.indexOf('@') === -1) { //邮箱中没有@,返回一个邮箱无效的错误json
response.statusCode = 400
response.setHeader('Content-Type', 'application/json;charset=utf-8')
response.write(`{
"email":"invalid"
}`)
} else { //存入db中的users数据库
let users = fs.readFileSync('./db/users', 'utf8')
console.log(users)
console.log(typeof users)
try {
users = JSON.parse(users) // []
console.log(typeof users)
} catch (exception) {
users = []
}
let inUse = false
for (let i = 0; i < users.length; i++) {
let user = users[i]
if (user.email === email) {
inUse = true
break;
}
}
if (inUse) {
response.statusCode = 400
response.write('email in use')
} else {
users.push({
email: email,
password: password
})
let usersString = JSON.stringify(users)
fs.writeFileSync('./db/users', usersString)
response.statusCode = 200
}
}
response.end()
})
}
/*接下来是登录的两个路由*/
else if (path === '/sign_in' && method === 'GET') {//同样GET是获取登录页面,POST是表单提交
let string = fs.readFileSync('./sign_in.html', 'utf8')
response.statusCode = 200
response.setHeader('Content-Type', 'text/html;charset=utf-8')
response.write(string)
response.end()
} else if (path === '/sign_in' && method === 'POST') {
readBody(request).then((body) => {
let strings = body.split('&') // ['email=1', 'password=2', 'password_confirmation=3']
let hash = {}
strings.forEach((string) => {
// 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
} = hash
var users = fs.readFileSync('./db/users', 'utf8')
try {
users = JSON.parse(users) // []
} catch (exception) {
users = []
}
let found
for (let i = 0; i < users.length; i++) {
if (users[i].email === email && users[i].password === password) {
found = true;//搜索数据库成功,那么把这个user对象的全部信息赋值给found
break
}
}
if (found) {//验证成功,设置登录Cookie为登录的邮箱,并放在响应里发给浏览器
let sessionID = (Math.random())*100000
sessions[sessionID] = {sign_in_email:`${email}`}
console.log("登录时填进去的sessions的id为:"+sessionID)
console.log("登录时填进去的sessions的email:"+sessions[sessionID].sign_in_email)
response.setHeader('Set-Cookie', `sessionID=${sessionID}`)
response.statusCode = 200
} else {
response.statusCode = 401
}
response.end()
})
} else {
response.statusCode = 404
response.setHeader('Content-Type', 'application/json;charset=utf-8')
response.write(`{
"error":"404error"
}`)
response.end()
}
})
server.listen(port)
console.log('监听 ' + port + ' 成功\n打开 http://localhost:' + port)
function readBody(request) { //封装读取请求体的函数
return new Promise((resolve, reject) => {
let body = []
//由于http接受数据是一小块一小块接受的,所以我们写代码也需要一块一块的接收,然后拼接在一起
request.on('data', (chunk) => {
body.push(chunk)
})
.on('end', () => {
body = Buffer.concat(body).toString();
resolve(body)
})
})
}
index.html:
<!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>首页</title>
</head>
<body>
<h1>欢迎 __user__ 登录</h1>
</body>
</html>
sign_in.html:
<!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>登录</title>
<style>
* {
margin: 0;
padding: 0;
}
body {
border: 1px solid red;
min-height: 100vh;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
}
.form-wrapper {
border: 1px solid #ddd;
padding: 20px;
min-width: 350px;
}
.form-wrapper .row{
margin: 10px 0;
}
.form-wrapper .row>label {
display: inline-block;
min-width: 4em;
}
</style>
</head>
<body>
<div class="form-wrapper">
<h1>登录</h1>
<form action="" id="signInForm">
<div class="row">
<label for="">邮箱</label>
<input type="text" name="email">
<span class="message"></span>
</div>
<div class="row">
<label for="">密码</label>
<input type="password" name="password">
<span class="message"></span>
</div>
<div class="row">
<input type="submit" value="登录">
</div>
</form>
</div>
<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script>
<script>
$form = $('#signInForm')
$form.on('submit', (e)=>{
e.preventDefault()
let hash = {}
let need = ['email', 'password']
need.forEach((name)=>{
let value = $form.find(`[name=${name}]`).val()
hash[name] = value
})
$form.find('.message').each((index, span)=>{
$(span).text('')
})
if(hash['email'] === '') {
$form.find('[name="email"]').siblings('.message').text("请填写邮箱")
return
}
if(hash['password'] === '') {
$form.find('[name="password"]').siblings('.message').text("请填写密码")
return
}
$.post('/sign_in', hash)
.then((response)=>{
window.location.href='/'
}, ()=>{
alert('邮箱或密码错误')
})
})
</script>
</body>
</html>
sign_up.html:
<!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>注册</title>
<style>
* {
margin: 0;
padding: 0;
}
body {
border: 1px solid red;
min-height: 100vh;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
}
.form-wrapper {
border: 1px solid #ddd;
padding: 20px;
min-width: 350px;
}
.form-wrapper .row{
margin: 10px 0;
}
.form-wrapper .row>label {
display: inline-block;
min-width: 4em;
}
</style>
</head>
<body>
<div class="form-wrapper">
<h1>注册</h1>
<form action="" id="signUpForm">
<div class="row">
<label for="">邮箱</label>
<input type="text" name="email">
<span class="message"></span>
</div>
<div class="row">
<label for="">密码</label>
<input type="password" name="password">
<span class="message"></span>
</div>
<div class="row">
<label for="">确认密码</label>
<input type="password" name="password_confirmation">
<span class="message"></span>
</div>
<div class="row">
<input type="submit" value="注册">
</div>
</form>
</div>
<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script>
<script>
$form = $('#signUpForm')
$form.on('submit', (e)=>{
e.preventDefault()
let hash = {}
let need = ['email', 'password', 'password_confirmation']
need.forEach((name)=>{
let value = $form.find(`[name=${name}]`).val()
hash[name] = value
})
$form.find('.message').each((index, span)=>{
$(span).text('')
})
if(hash['email'] === '') {
$form.find('[name="email"]').siblings('.message').text("请填写邮箱")
return
}
if(hash['password'] === '') {
$form.find('[name="password"]').siblings('.message').text("请填写密码")
return
}
if(hash['password_confirmation'] === '') {
$form.find('[name="password_confirmation"]').siblings('.message').text("请填写密码")
return
}
if(hash["password"] !== hash['password_confirmation']) {
$form.find('[name="password_confirmation"]').siblings('.message').text("密码不匹配")
return
}
$.post('/sign_up', hash)
.then((response)=>{
let message = response
console.log(message)
if (message.email && message.email === 'successed') {
$form.find('[name="email"]').siblings('.message')
.text('注册成功')
}
}, (xhr)=>{
console.log(xhr)
//服务器端设置了application/json头
let {message}=xhr.responseJSON
console.log(message)
if (message.email && message.email === 'invalid') {
$form.find('[name="email"]').siblings('.message')
.text('邮箱格式错误')
} else if (message.email && message.email === 'used') {
$form.find('[name="email"]').siblings('.message')
.text('邮箱已被注册')
}
})
})
</script>
</body>
</html>
部分界面截图:
六、心得体会
这次实验我主要做了两方面的内容,一方面是有机农场管理系统的继续完善,另一方面是系统模块功能的扩展,实现利用Cookie的登录注册功能。仔细研究了去年的web项目,在有机农场管理系统的基础上更改了原系统的CSS和HTML等,使界面更加美观。又在原系统基础上扩展了登录功能,实现了登录注册功能。并且利用了cookie识别用户的身份。
做实验的时候我尽量不看电子书,不看PPT,凭自己印象做,本来以为自己已经掌握得很好了,但是在实际敲代码的时候还是出现了问题。主要是记忆不准,不确定自己敲的对不对。尤其是JavaScript部分,学的时间还是有点少,所以做起来还是有点生疏。看来平时还是应该多动手,只有自己动手敲了才能真正掌握。
但是书也是很重要的,我觉得老师传的那几本电子书在将网页制作讲的很详细,也很有趣。尤其是对很多概念的理解,我们平时在网上找到的一些教程往往只是写了某元素有什么作用,而元素背后的一些概念来源,元素使用的时候会出现的各种情况都没有详细的说明。网上的教程更像是使用手册、说明书,需要你了解web的基本概念和模式之后使用才比较方便。对于我这种初学者,理解起来会比较困难。而且网上的信息是零碎的,不一定符合我们的需求,想要提高自己最方便快捷的方式还是看书学会知识,而不是遇到不会的地方再到处搜解决方法。
一般遇见不懂的地方首先是看别人的博客,找一找相似的问题。在实验项目结束后,我把课上没有弄太懂和不熟的地方总结了一下,并且把这些内容加到了我的CSDN博客里。Web还是应该多练习,多总结。我感觉HTML和CSS的知识点比较零碎,需要记一下笔记和关键的知识点,方便后期做项目。而且网上有很多做网页的技巧,通过我们已经学过的简单元素就可以实现,平时也可以多积累这些有意思的知识。出过的错要及时问,及时解决,才能不断进步越来越熟练。
安装nodejs之类的过程在实验报告里没有写,直接上nodejs官网下载就好了,网上说初学者建议直接下载安装版,无需自己去编译。nodejs安装版和安装其他软件一样,无门槛。但是我刚开始出了许多莫名其妙的错误,启动的bat文件总是打不开闪退,node也无法运行。后来才发现是因为express没有装好,而且文件必须要用管理员身份运行才可以。
本次实验加深了我对web网页制作的理解,并且通过知识的综合应用,加深了对HTML、CSS和JavaScript的理解。再次感受到了node.js的方便和强大。Node打破了过去JavaScript只能在浏览器中运行的局面,前后端编程环境统一,可以大大降低前后端转换所需要的上下文交换的额代价。看学长的源码看到一半,我又发现很多地方我不是很懂,问了些学长学姐,发现是因为我的JavaScript基础不够,所以最近又先去巩固js的基础......真的是一波三折。
Node.js 的推出,不仅从工程化的角度自动化掉更多琐碎费时的工作,更打破了前端后端的语言边界,让 JavaScript 流畅的运行在服务器端。遇到很多困难,但由于可以参照源码和讲解,所以最后都顺利解决了。把不会的知识点记下来写成博客,日积月累,为以后的学习打下更牢固的基础。
此次实验让我学到了很多平时不会注意到的点,比如代码的写法规范,网页的建造流程。希望以后写代码的时候能够更加注意这些细节。
总结下这次实验项目设计,花了半个多月做下来,可能学的东西比我整个学期的实验课学到的还多。希望以后可以继续改进,能做出好的作品。
七、参考博客
1、网页注册登录功能的实现以及Cookie的利用
https://www.jianshu.com/p/58760ef27acd
2、使用cookie做用户登录的过程详解
https://blog.csdn.net/looksunli/article/details/9799395
3、9 个强大的 JavaScript 小技巧
https://segmentfault.com/a/1190000021276628
- CSS居中完全指南——构建CSS居中决策树
来源:CSDN
作者:xiehuiru
链接:https://blog.csdn.net/xiehuiru/article/details/103709429