如何通过node.js来实现项目的登录和注册功能 通过node.js可以实现中小型项目的后端搭建基于js的语法达到全栈开发的效果。1.创建项目在文件夹中自定义命名一个文件在终端打开初始化包管理配置文件npm init -y安装新版本的express:npm i express在项目根目录下创建app.js文件作为整个项目的入口文件端口号自定义避免冲突const express require(express) const app express() -----中间部分------ app.listen(8082,(){ console.log(Express server running at http://127.0.0.1:8082); })配置cors跨域安装cors中间件npm i cors在app.js中导入并配置cors中间件const cors require(cors) app.use(cors())配置解析表单数据的中间件解析application/x-www-form-urlencoded格式的表单数据app.use(express.urlencoded({extended:false}))在项目根目录中创建router文件夹用来存放所有的路由模块创建router_handler文件夹用来存放所有的路由处理函数模块在router文件夹中创建user.js文件作为用户的路由模块const express require(express) const router express.Router() router.post(/reguser,(req,res){ res.send(注册成功) }) router.post(/login,(req,res){ res.send(登录成功) }) module.exports router然后在app.js文件中导入使用用户路由模块const userRouter require(./router/user) app.use(/api,userRouter)在router_handler文件夹下创建user.js文件抽离用户路由模块中的处理函数使用exports对象向外共享两个处理函数exports.reguser (req,res) { res.send(注册成功) } exports.login (req,res) { res.send(登录成功) }将/router/user.js中的代码进行修改const express require(express) const router express.Router() // 导入用户路由处理模块 const userHandler require(../router_handler/user) router.post(/reguser,userHandler.register) //注册 router.post(/login,userHandler.login) //登录 module.exports router2.创建数据库推荐使用Navicat定义数据库名称新建数据表设计表结构如图所示id为主键默认为自增其他字段统一字符集utf8mb4排序规则utf8mb4_0900_ai_ci在项目终端中安装mysql模块npm i mysql2在根目录创建db/index.js文件用来创建数据库的连接对象const mysql require(mysql2) const db mysql.createPool({ host:127.0.0.1, user:root, password:123456, database:my_db_01 }) module.exports db3.注册首先检测表单数据合法性// 获取客户端提交到服务的用户信息 const userinfo req.body // 对表单中的数据进行合法校验 if(!userinfo.username || !userinfo.password){ return res.send({ status:1, message:用户名或密码不合法 }) }检测用户名是否被占用导入数据库操作模块定义SQL语句// 导入数据库操作模块 const db require(../db/index) // 定义sql语句查询用户名是否被占用 const sqlStr select * from ev_users where username?执行SQL语句判断用户名是否被占用db.query(sqlStr,userinfo.username,(err,result){ // 执行SQL语句失败 if(err){ return res.send({ status:1, message:err.message }) } // 判断用户名是否被占用 if(result.length 0){ return res.send({ status:1, message:用户名已被占用请重新输入 }) } })对密码进行加密处理安装指定版本的bcryptjsnpm install bcryptjs在/router_handler/user.js文件中导入bcryptjs// 导入bcryptjs模块用于密码加密 const bcrypt require(bcryptjs)调用 bcrypt.hashSync()对密码进行加密userinfo.password bcrypt.hashSync(userinfo.password,10)插入新用户定义插入的SQL语句const sql insert into ev_users set ?调用db.query()执行SQL语句插入新用户db.query(sql,{username:userinfo.username,password:userinfo.password},(err,result){ // 判断SQL语句是否执行成功 if(err)return res.send({ status:1,message:err.message}) // 判断影响行数是否为1 if(result.affectedRows ! 1)return res.send({ status:1,message:注册失败}) // 注册成功 res.send({ status:0,message:注册成功}) })对res.send()代码进行优化在app.js中在所有路由之前声明一个全局中间件为res对象挂载一个res.cc()的函数app.use((req,res,next){ // status默认值为1表示失败的情况 // err的值可能是一个错误对象也可能是一个字符串 res.cc (err,status1){ res.send({ status, message:err instanceof Error ? err.message : err }) } next() })然后将所有的res.send()代码进行修改// 注册用户的处理函数 exports.reguser (req,res){ // 获取客户端提交到服务的用户信息 const userinfo req.body // 定义sql语句查询用户名是否被占用 const sqlStr select * from ev_users where username? db.query(sqlStr,userinfo.username,(err,result){ // 执行SQL语句失败 if(err){ return res.cc(err) } // 判断用户名是否被占用 if(result.length 0){ return res.cc(用户名已被占用请重新输入) } // 调用 bcrypt.hashSync()对密码进行加密 userinfo.password bcrypt.hashSync(userinfo.password,10) // 定义插入新用户的SQL语句 const sql insert into ev_users set ? db.query(sql,{username:userinfo.username,password:userinfo.password},(err,result){ // 判断SQL语句是否执行成功 if(err)return res.cc(err) // 判断影响行数是否为1 if(result.affectedRows ! 1)return res.cc(注册用户失败请稍后重试) // 注册成功 res.cc(注册成功) }) }) }优化表单数据验证安装hapi/joi包npm i hapi/joi安装escook/express-joi中间件实现自动对表单数据进行验证npm i escook/express-joi新建/schema/user.js用户信息验证规则模块// 导入定义验证规则的包 const joi require(joi) // 定义用户名和密码的验证规则 const username joi.string().alphanum().min(1).max(10).required() const password joi.string().pattern(/^[\S]{6,12}$/).required() // 定义验证注册和登录表单数据的规则对象 exports.reg_login_schema { body:{ username, password } }修改router/user.js中的代码const express require(express) const router express.Router() // 导入用户路由处理函数模块 const userHandler require(../router_handler/user) // 导入验证数据的中间件 const expressJoi require(escook/express-joi) // 导入需要的验证规则对象 const {reg_login_schema} require(../schema/user) // 注册新用户 router.post(/reguser,expressJoi(reg_login_schema),userHandler.reguser) // 登录 router.post(/login,userHandler.login) module.exports router在app.js的全局错误级别中间件中捕获验证失败的错误并把验证失败的结果响应给客户端const joi require(joi) // 定义错误级别的中间件 app.use((err,req,res,next){ // 验证失败导致的错误 if(err instanceof joi.ValidationError) return res.cc(err) // 未知的错误 res.cc(err) })4.登录验证登录表单的数据是否合法修改router/user.js中的登录代码/ 登录 router.post(/login,expressJoi(reg_login_schema),userHandler.login)在router_handler文件中根据用户名查询用户的数据// 登录的处理函数 exports.login (req,res){ // 接收表单数据 const userinfo req.body // 定义SQL语句 const sql select * from ev_users where username? // 执行SQL语句根据用户名查询用户的信息 db.query(sql,userinfo.username,(err,results){ // 执行SQL语句失败 if(err)return res.cc(err) // 执行SQL语句成功但是获取到的数据条数不等于1 if(results.length ! 1)return res.cc(登录失败) }) }判断用户输入的密码是否正确const compareResult bcrypt.compareSync(userinfo.password,results[0].password) if(!compareResult)return res.cc(登录失败)生成JWT的token字符串通过ES6的高级语法快速剔除密码和头像的值const user { ...results[0] , password: , user_pic:}安装生成token字符串的包npm i jsonwebtoken在/router_handler/user.js 头部导入jsonwebtoken包// 导入生成token的包 const jwt require(jsonwebtoken)创建config.js 文件并向外共享加密和还原Token的jwtSecretKey字符串// 这是一个全局的配置文件 module.exports { // 这是加密和解密token的密钥 secretKey:fengrui, // 这是token的过期时间 expiresIn:10h }在router_handler/user.js文件中将用户信息对象加密成Token字符串// 导入配置文件 const config require(../config) // 对用户的信息进行加密生成token字符串 const tokenStr jwt.sign(user,config.secretKey,{expiresIn:config.expiresIn})将生成的token字符串响应给客户端// 调用res.send()将token响应给客户端 res.send({ status:0, message:登录成功, token: Bearer tokenStr })配置解析token的中间件npm i express-jwt在app.js中注册路由之前配置解析token的中间件// 一定要在路由之前配置解析token的中间件 const { expressjwt } require(express-jwt); const config require(./config); // 配置 JWT 解析中间件 app.use( expressjwt({ secret: config.secretKey, algorithms: [HS256], }).unless({ path: [/^\/api/] }) // 排除 /api 开头的接口 );在app.js中的错误级别中间件里面捕获并处理Token认证失败后的错误// 定义错误级别的中间件 app.use((err,req,res,next){ // 验证失败导致的错误 if(err instanceof joi.ValidationError) return res.cc(err) // 解析token失败导致的错误 if(err.name UnauthorizedError) return res.cc(身份认证失败) // 未知的错误 res.cc(err) })5.Apipost测试测试注册接口测试登录接口测试其他接口6.相关的安装包版本信息仅供参考package.json文件{ name: api_server, version: 1.0.0, description: , main: index.js, scripts: { test: echo \Error: no test specified\ exit 1 }, keywords: [], author: , license: ISC, type: commonjs, dependencies: { escook/express-joi: ^1.1.1, bcryptjs: ^3.0.3, cors: ^2.8.6, express: ^4.21.1, express-jwt: ^8.4.1, joi: ^17.13.3, jsonwebtoken: ^9.0.3, mysql2: ^3.22.2 } }

相关新闻

最新新闻

Java Agent 异常处理的可选性:从 Optional 到 CompletableFuture 的降级策略实践

Java Agent 异常处理的可选性:从 Optional 到 CompletableFuture 的降级策略实践

如果把 Agent 的异常处理写成传统的try-catch,大概率会在第一个真实故障面前失灵。这不是危言耸听,而是 Agent 应用与传统后端服务的本质差异决定的:Agent 的执行结果不确定、调用链不固定、外部依赖多,而且它并不是每一次失败都值…

2026/8/30 7:38:08
Minimax H3提示词Skill实战指南:从安装到效果验证

Minimax H3提示词Skill实战指南:从安装到效果验证

说实话,最近视频生成模型圈子里讨论度最高的名字之一就是 Minimax H3。很多人第一眼看到演示视频时,第一反应都是“这是 CG 吧”,结果发现确实是模型直出。但等自己真正部署完、跑起来之后,反馈却往往两极分化:有人觉得…

2026/8/30 7:38:08
AI进入大学:教学考核如何重构?从Carson Gross见解到RAG实践

AI进入大学:教学考核如何重构?从Carson Gross见解到RAG实践

最近在技术社区里,Carson Gross 的一段分享《AI and the University》被反复讨论。如果你熟悉 htmx 和《Hypermedia Systems》这本书,应该对这个名字不陌生。他作为长期在 Web 开发领域坚持“简化”理念的技术人,这次把目光投向了大学教育&am…

2026/8/30 7:38:08
大模型为何“不知道自己在做什么”?Agent工程中的自验证与可靠性实践

大模型为何“不知道自己在做什么”?Agent工程中的自验证与可靠性实践

“OpenAI just proved AI has no idea what its doing (July) [video]”这段带有挑衅意味的视频标题在技术社区流传时,真正值得关注的不是“OpenAI 又要炒作什么”,而是一个反复出现的工程现象:AI 能生成非常自信、流畅、结构完整的回答&…

2026/8/30 7:38:08
基于Claude Tag的标签驱动值班:从请求埋点到连接错误排查

基于Claude Tag的标签驱动值班:从请求埋点到连接错误排查

在实际依赖 Claude 模型的业务系统里,值班工作很少只是“看日志、找原因”这么简单。真正麻烦的是:请求量大之后,同一个错误可能来自多个服务、多个用户、多个批次,值班人员收到告警却不知道这条错误影响谁、该由谁处理、是不是已…

2026/8/30 7:38:08
从vibe coding到spec coding:打造可控的AI辅助编程工作流

从vibe coding到spec coding:打造可控的AI辅助编程工作流

当“Im done coding with AI”这类标题开始频繁出现在开发者社区时,很多人的真实态度并不是“我再也不碰 AI”,而是被 AI 编程工具“看起来很快、实际收尾很慢”的体验反复折磨之后,决定重新审视自己的使用方式。早期的兴奋很容易理解&#x…

2026/8/30 7:33:08