一、创建html页面

创建4个页面,index.html、register.html、sign_in.html、home.html

  • index.html 默认主页
  • register.html 用于注册账号
  • sign_in.html 用于登录账号
  • home.html 用于显示登录后的页面

主要代码片段

register.html

  1. <form id="registerForm">
  2. <div>
  3. <label for="">用户名:<input type="text" name="name" id=""></label>
  4. </div>
  5. <div>
  6. <label for="">密码:<input type="password" name="password" id=""></label>
  7. </div>
  8. <div>
  9. <button type="submit">注册</button>
  10. </div>
  11. </form>
  12. <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
  13. <script>
  14. let $form = $('#registerForm')
  15. $form.on('submit', (e) => {
  16. e.preventDefault()
  17. const name = $form.find("input[name=name]").val()
  18. const password = $form.find('input[name=password').val()
  19. console.log(name, password)
  20. // pass AJAX post data
  21. $.ajax({
  22. method: 'post',
  23. url: '/register',
  24. contentType: 'text/json; charset=UTF-8',
  25. data: JSON.stringify({
  26. name, // name: name
  27. password // password: password
  28. })
  29. }).then(() => {
  30. alert('注册成功')
  31. location.href = '/sign_in.html'
  32. }, () => {})
  33. })
  34. </script>

sign_in.html

  1. <form id="signInForm">
  2. <div>
  3. <label for="">用户名:<input type="text" name="name" id=""></label>
  4. </div>
  5. <div>
  6. <label for="">密码:<input type="password" name="password" id=""></label>
  7. </div>
  8. <div>
  9. <button type="submit">登录</button>
  10. </div>
  11. </form>
  12. <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
  13. <script>
  14. let $form = $('#signInForm')
  15. $form.on('submit', (e) => {
  16. e.preventDefault()
  17. // get name password
  18. const name = $form.find("input[name=name]").val()
  19. const password = $form.find('input[name=password').val()
  20. // pass AJAX post data
  21. $.ajax({
  22. method: 'POST',
  23. url: '/sign_in',
  24. contentType: 'text/json; charset=UTF-8',
  25. data: JSON.stringify({
  26. name,
  27. password
  28. })
  29. }).then(() => {
  30. alert('登录成功')
  31. location.href = '/home.html'
  32. }, () => {})
  33. })
  34. </script>

home.html

  1. <p>
  2. {{loginStatus}}
  3. </p>
  4. <p>
  5. 你好,{{user.name}}
  6. </p>
  7. <p>
  8. <a href="sign_in.html">登录</a>
  9. </p>

二、Node服务器

  1. var http = require('http')
  2. var fs = require('fs')
  3. var url = require('url')
  4. var port = process.argv[2]
  5. if (!port) {
  6. console.log('请输入指定端口。如:\nnode server.js 8888')
  7. process.exit(1)
  8. }
  9. var server = http.createServer(function (request, response) {
  10. var parsedUrl = url.parse(request.url, true)
  11. var pathWithQuery = request.url
  12. var queryString = ''
  13. if (pathWithQuery.indexOf('?') >= 0) {
  14. queryString = pathWithQuery.substring(pathWithQuery.indexOf('?'))
  15. }
  16. var path = parsedUrl.pathname
  17. var query = parsedUrl.query
  18. var method = request.method
  19. /******** main start ************/
  20. // 读取 session 文件,转化为对象
  21. const session = JSON.parse(fs.readFileSync('./session.json').toString())
  22. if (path === '/sign_in' && method === 'POST') {
  23. // 读数据库
  24. let userArray = JSON.parse(fs.readFileSync('./database/users.json'))
  25. const array = []
  26. // 每次接受数据就添加进数组
  27. request.on('data', (chunk) => {
  28. array.push(chunk)
  29. })
  30. request.on('end', () => {
  31. // 转化字符串
  32. const string = Buffer.concat(array).toString()
  33. // 在转化为对象
  34. const obj = JSON.parse(string)
  35. // 找到符合的 user
  36. const user = userArray.find(user => user.name === obj.name && user.password === obj.password) // 成功返回符合的对象,失败返回undefined
  37. if (user === undefined) { // 失败
  38. response.statusCode = 400
  39. response.setHeader('content-Type', 'text/JSON; charset=UTF-8')
  40. response.end(`{"errorCode":4001}`)
  41. } else { // 成功
  42. response.statusCode = 200
  43. // 设置 Cookie
  44. const random = Math.random()
  45. session[random] = {
  46. user_id: user.id
  47. }
  48. // 写入数据
  49. fs.writeFileSync('./session.json', JSON.stringify(session))
  50. response.setHeader("Set-Cookie", `'session_id=${random}; HttpOnly'`)
  51. response.end()
  52. }
  53. })
  54. } else if (path === '/home.html') {
  55. // 获取 Cookie
  56. const cookie = request.headers['cookie']
  57. let sessionId
  58. try { // 读取 Cookie 中的 id 值
  59. sessionId = cookie.split(';').filter(s => s.indexOf('session_id=') >= 0)[0].split('=')[1]
  60. } catch (error) {}
  61. if (sessionId && session[sessionId]) {
  62. // 从 session 中读取对应的值
  63. const userId = session[sessionId].user_id
  64. // 读数据库
  65. let userArray = JSON.parse(fs.readFileSync('./database/users.json'))
  66. // 找到符合的 user
  67. let user = userArray.find(user => user.id === userId)
  68. const homeHtml = fs.readFileSync('./public/home.html').toString()
  69. let string
  70. if (user) {
  71. string = homeHtml.replace('{{loginStatus}}', '已登录').replace('{{user.name}}', user.name)
  72. response.write(string)
  73. }
  74. } else {
  75. // 读取源文件内容
  76. const homeHtml = fs.readFileSync('./public/home.html').toString()
  77. // 替换文字
  78. const string = homeHtml.replace('{{loginStatus}}', '未登录').replace('{{user.name}}', '')
  79. response.write(string)
  80. }
  81. response.end()
  82. } else if (path === '/register' && method === 'POST') {
  83. response.setHeader('Content-Type', 'text/html; charset=UTF-8')
  84. // read database
  85. let userArray = JSON.parse(fs.readFileSync('./database/users.json')) // read database
  86. const array = []
  87. request.on('data', (chunk) => {
  88. array.push(chunk)
  89. })
  90. request.on('end', () => {
  91. // convert string
  92. const string = Buffer.concat(array).toString()
  93. // convert obj
  94. const obj = JSON.parse(string)
  95. // last user id
  96. const lastUser = userArray[userArray.length - 1]
  97. // new user
  98. const newUser = {
  99. id: lastUser ? lastUser.id + 1 : 1,
  100. name: obj.name,
  101. password: obj.password
  102. }
  103. userArray.push(newUser)
  104. // write data
  105. fs.writeFileSync('./database/users.json', JSON.stringify(userArray))
  106. })
  107. response.end()
  108. } else {
  109. response.statusCode = 200
  110. let content
  111. // setting index
  112. const filePath = path === '/' ? '/index.html' : path
  113. // judge type
  114. const index = filePath.lastIndexOf('.')
  115. const suffix = filePath.substring(index)
  116. const fileType = {
  117. '.html': 'text/html',
  118. '.css': 'text/css',
  119. '.js': 'text/javascript'
  120. }
  121. response.setHeader('Content-Type', `${fileType[suffix] || "text/html"};charset=utf-8`)
  122. try {
  123. content = fs.readFileSync(`./public${filePath}`)
  124. } catch (error) {
  125. content = '文件路径不存在'
  126. response.statusCode = 404
  127. }
  128. response.write(content)
  129. response.end()
  130. }
  131. /******** main end ************/
  132. })
  133. server.listen(port)
  134. console.log('监听 ' + port + ' 成功!请输入下列地址访问\nhttp://localhost:' + port)

三、主要思路

register.html

使用jQuery的ajax将数据发送请求 /register 给后端,成功则跳转到 sign_in.html

数据需要使用 JSON.stringify 转化为字符串在提交

/register

读取 users.json 的数据,创建一个空数组,将传递过来的参数 push 进去。将数组转换为字符串,在转换为对象。
获取数据库中最小的 id 值,将数据组成新的对象,添加进入 数据库 中。

sign_in.html

使用ajax将数据发送请求 /sign_in 给后端,成功则跳转 home.html

/sign_in

读取 users.json 的数据,创建一个空数组,将传递过来的参数 push 进去。将数组转换为字符串,在转换为对象。
在读取后的数据库中,查找有没有符合条件的 user,成功返回读取后的对象,失败返回 undefined。
如果成功,设置随机数,将 随机数的值 与 user的id 绑定。并添加到 session.json 中。然后 setHeader,将cookie发送到浏览器。

/home

获取登入成功后 cookie 的值。读取 session 中对应的随机数。如果随机数和session对应的随机数值存在,就显示已登录,否则显示未登录