HyperExpress经验

一、HyperExpress链接
https://gitee.com/gridsoft/hyper-express#/gridsoft/hyper-express/blob/master/docs/Router.md

二、错误处理中间件的示例:

const  express  =  require('express');
const  app  =  express();
const  PORT  =  3000;

//  假设我们有一个异步函数可能会抛出错误
async  function  asyncFunctionThatMightFail()  {
      throw  new  Error('异步操作错误');
}

//  定义一个使用  try/catch  的路由来处理错误
app.get('/async-route',  async  (req,  res,  next)  =>  {
      try  {
          //  调用可能会失败的异步函数
          await  asyncFunctionThatMightFail();
          res.json({  message:  '操作成功'  });
      }  catch  (error)  {
          //  将错误传递给错误处理中间件
          next(error);
      }
});

//  定义统一的错误处理中间件
app.use((err,  req,  res,  next)  =>  {
      //  你可以在这里添加更复杂的逻辑,例如日志记录
      console.error(err.stack);

      //  设置错误状态,如果未设置,默认为500
      const  status  =  err.status  ||  500;

      //  响应客户端
      res.status(status).json({
          error:  {
              message:  err.message
          }
      });
});

//  一个正常路由,作为示例
app.get('/',  (req,  res)  =>  {
      res.send('主页');
});

//  启动服务器
app.listen(PORT,  ()  =>  {
      console.log(`服务器正在监听端口  ${PORT}`);
});

 

三、路由中的错误处理:

在  Express  中,路由函数检测错误的方式通常依赖于以下几种机制:

1、同步代码中的错误抛出:
如果在同步代码中出现错误(例如,调用一个可能会抛出错误的函数),你可以直接抛出这个错误。Express  会将抛出的错误视为一个未被处理的异常,并自动将其传递给错误处理中间件。
app.get('/sync-error-route',  function(req,  res)  {
  //  假设这个函数可能会抛出错误
  if  (someCondition)  {
    throw  new  Error('同步错误发生了');
  }
  res.send('没有错误发生');
});
2、异步代码中的 next 函数: 对于异步代码(例如,通过回调、Promises、async
/await),你不能直接抛出错误,因为它们会在异步操作完成后的某个时刻被捕获。在这种情况下,你需要使用 next 函数手动传递错误。 app.get('/async-error-route', function(req, res, next) { someAsyncFunction().then(result => { // 处理结果 res.send('异步操作成功'); }).catch(error => { // 使用 next 传递错误 next(error); }); });
3、或者对于使用 async
/await 的异步代码: app.get('/async-await-error-route', async function(req, res, next) { try { await someAsyncFunction(); res.send('异步操作成功'); } catch (error) { // 使用 next 传递错误 next(error); } });
4、中间件错误处理: 如果你使用了中间件,并且中间件中发生了错误,同样可以通过 next 传递错误。 app.use(
function(req, res, next) { // 假设这个中间件可能会发生错误 if (someCondition) { next(new Error('中间件错误')); } else { next(); // 继续下一个中间件或路由处理函数 } });
5、错误处理中间件: Express 允许你定义错误处理中间件,它会在发生错误时被调用。这个中间件函数接收四个参数:err, req, res, 和 next。当错误通过 next 传递时,Express 会查找第一个匹配的错误处理中间件来处理这个错误。 app.use(
function(err, req, res, next) { console.error(err.stack); res.status(500).send('发生了一个错误!'); });
总的来说,Express 路由函数检测错误的方式依赖于开发者如何处理同步和异步代码中的错误,以及他们如何使用 next 函数传递这些错误。正确地使用 next 函数和错误处理中间件是管理 Express 应用程序中错误的关键。

 

四、以下是一个示例,展示了如何在认证中间件中添加参数,并在后续路由中使用它们:

npm  install  jsonwebtoken

const  jwt  =  require('jsonwebtoken');
const  express  =  require('express');
const  app  =  express();

//  假设这是一个秘密密钥,实际应用中应保存在环境变量或配置文件中
const  secretKey  =  'your-secret-key';

//  认证中间件
const  authenticate  =  (req,  res,  next)  =>  {
      const  token  =  req.headers.authorization;

      if  (!token)  {
          return  res.status(401).json({  error:  '没有提供token'  });
      }

      jwt.verify(token,  secretKey,  (err,  decoded)  =>  {
          if  (err)  {
              return  res.status(403).json({  error:  '无效的token'  });
          }

          //  在req对象上添加用户信息,这样后续路由可以使用这些信息
          req.user  =  {
              id:  decoded.id,  //  假设解码的token中包含用户ID
              username:  decoded.username,  //  假设解码的token中包含用户名
              roles:  decoded.roles  //  假设解码的token中包含用户角色
          };

          //  继续下一个中间件(即路由处理器)
          next();
      });
};

//  使用中间件
app.use('/protected',  authenticate);  //  假设所有以'/protected'开头的路由都需要认证

//  定义一个受保护的路由,使用req.user中的信息
app.get('/protected/userinfo',  (req,  res)  =>  {
      //  在这里使用req.user中的信息
      res.json({
          message:  'User  information',
          user:  req.user
      });
});

//  监听端口
app.listen(3000,  ()  =>  {
      console.log('Server  is  running  on  http://localhost:3000');
});

 

五、内存泄漏处理

在Node.js和Express框架长期运行的过程中,内存泄漏是一个常见的问题。内存泄漏会导致内存占用不断增加,最终可能导致应用程序性能下降甚至崩溃。以下是处理这种情况的一些最佳实践:

内存泄漏检测和监控
使用监控工具:使用如memwatch-next、heapdump、node-mtrace等工具来监控和检测内存泄漏。
使用性能分析工具:使用如clinic.js等工具定期对应用程序进行性能分析,以识别潜在的内存泄漏。
代码层面优化
闭包和作用域:避免在全局作用域或者闭包中保留大量数据的引用,这可能导致这些数据无法被垃圾回收。
事件监听器:确保移除不再需要的事件监听器,因为未移除的事件监听器可能导致内存泄漏。
定时器和回调:未清理的定时器或回调函数也可能导致内存泄漏。确保取消或清理未使用的定时器。
流和文件操作:确保正确处理流(Stream)和文件描述符,关闭不再使用的流和文件。
部署和运行时优化
使用最新版本的Node.js:最新版本的Node.js通常包含了对垃圾回收和内存管理的改进。
限制内存使用:在启动Node.js应用时,可以使用--max-old-space-size参数限制V8引擎可以使用的最大内存量。
集群模式:使用Node.js的集群模块来运行多个子进程,每个子进程都有自己的内存空间。这样可以避免单个进程的内存泄漏影响整个应用程序。 到达最大内存时docker重启。
定期重启:设置应用程序定期重启,这可以是一个简单的解决方法,但不是根本的解决方案。

 

六、prisma数据库接口

如果你的数据库已经存在,你仍然可以使用Prisma来连接和管理它。以下是你可以遵循的步骤:

1、安装Prisma  CLI(如果你还没有安装):
npm  install  -g  prisma
初始化Prisma项目(如果你还没有初始化):
prisma  init
在初始化过程中,选择“SQLite”作为数据库类型(即使你打算使用PostgreSQL),因为Prisma  CLI目前不支持直接选择PostgreSQL作为初始化选项。你可以稍后更改schema.prisma文件来配置PostgreSQL。

2、配置schema.prisma文件:
打开prisma/schema.prisma文件,并更新数据源配置为PostgreSQL,同时指定正确的连接参数:
//  schema.prisma
datasource  db  {
    provider  =  "postgresql"
    url        =  env("DATABASE_URL")
}
generator  client  {
    provider  =  "prisma-client-js"
}
确保你的环境变量DATABASE_URL指向你的PostgreSQL数据库,格式如下:
plaintext
postgresql://[USERNAME]:[PASSWORD]@[HOST]:[PORT]/[DATABASE]?schema=public
3、同步现有数据库结构: 如果你有一个现有的数据库结构,你可以使用Prisma的introspect命令来自动检测和同步数据库模型: prisma introspect 这会生成一个基于你现有数据库结构的Prisma Schema。 4、更新数据库模型(如果需要): 如果introspect命令生成的模型不满足你的需求,你可以手动编辑schema.prisma文件来更新模型。 5、测试连接和查询: 使用Prisma Client在代码中测试数据库连接和执行查询: import { PrismaClient } from '@prisma/client'; const prisma = new PrismaClient(); async function main() { // 测试查询 const users = await prisma.user.findMany(); console.log('Existing users:', users); } main() .catch((e) => { throw e; }) .finally(async () => { await prisma.$disconnect(); }); 6、请记住,在处理现有数据库时,确保Prisma Schema中的模型与数据库的实际结构相匹配,以避免数据丢失或结构冲突。如果你只是想要使用Prisma作为ORM来查询和管理数据库,而不改变数据库结构,那么确保不要运行会修改数据库结构的迁移。
初始化prisma:
export  PRISMA_CLIENT_POOL_TIMEOUT=30
export  PRISMA_CLIENT_POOL_SIZE=10

const  prisma  =  new  PrismaClient({
    //  如果你想要覆盖环境变量中的设置,可以在这里直接设置
    //  这里是可选的,如果你已经在环境变量中设置了连接池参数,就不需要在这里设置
    //  pool:  {
    //     timeout:  Number(process.env.PRISMA_CLIENT_POOL_TIMEOUT),
    //     max:  Number(process.env.PRISMA_CLIENT_POOL_SIZE),
    //  },
});

 

六、路由举例

const  express  =  require('express');
const  app  =  express();
const  port  =  3000;

app.use(express.json());  //  for  parsing  application/json

//  获取用户列表
app.get('/users',  async  (req,  res)  =>  {
      try  {
          const  users  =  await  prisma.user.findMany();
          res.json(users);
      }  catch  (error)  {
          console.error('Error  fetching  users:',  error);
          res.status(500).json({  message:  'Internal  server  error'  });
      }
});

//  创建新用户
app.post('/users',  async  (req,  res)  =>  {
      try  {
          const  newUser  =  await  prisma.user.create({
              data:  req.body,
          });
          res.status(201).json(newUser);
      }  catch  (error)  {
          console.error('Error  creating  user:',  error);
          res.status(500).json({  message:  'Internal  server  error'  });
      }
});

//  更新用户
app.put('/users/:id',  async  (req,  res)  =>  {
      const  {  id  }  =  req.params;
      try  {
          const  updatedUser  =  await  prisma.user.update({
              where:  {  id:  parseInt(id)  },
              data:  req.body,
          });
          res.json(updatedUser);
      }  catch  (error)  {
          console.error('Error  updating  user:',  error);
          res.status(500).json({  message:  'Internal  server  error'  });
      }
});

//  删除用户
app.delete('/users/:id',  async  (req,  res)  =>  {
      const  {  id  }  =  req.params;
      try  {
          await  prisma.user.delete({
              where:  {  id:  parseInt(id)  },
          });
          res.json({  message:  'User  deleted  successfully'  });
      }  catch  (error)  {
          console.error('Error  deleting  user:',  error);
          res.status(500).json({  message:  'Internal  server  error'  });
      }
});

app.listen(port,  ()  =>  {
      console.log(`Server  is  running  on  http://localhost:${port}`);
});

 

 




HyperExpress需要Node.js版本14+,可以使用节点包管理器(npm)安装。

npm i hyper-express


posted @ 2024-04-10 10:59  pearlcity  阅读(51)  评论(0编辑  收藏  举报