express:项目本地中间件扩展 Express.Request

Posted

技术标签:

【中文标题】express:项目本地中间件扩展 Express.Request【英文标题】:express: project-local middleware extending Express.Request 【发布时间】:2016-04-07 06:38:57 【问题描述】:

我正在开发基于express 并使用 TypeScript 1.7 编写的节点服务器。我正在使用一些特定于项目的中间件,它们扩展了现有的快速请求或响应接口,但我还不能让它完全工作(没有 tsc 抱怨在 reqres 中找不到 X)。我找到了其他 questions 关于这个问题,但它们要么已经过时(我猜),要么解决方案不是直截了当的。

我查看了existing middleware 的定义,但如果不手动编写单独的 d.ts 文件并在 typings/tsd.d.ts 中引用它们,我就无法让它工作。这是我的设置:

// middleware/foobar.ts
declare module Express 
  export interface Request 
    foobar?: string;
  


/* my project-related middleware extends the request by `foobar` */
export = function(req: Express.Request, res, next) 
  req.foobar = 'FooBar';
  next();
;

// main.ts
import express = require('express');

var app = express();

app.use(require('./middleware/foobar'));

app.get('/foobar', (req, res) => 
  /* tsc: Property 'foobar' does not exist on type 'Request' */
  res.send(req.foobar);
);

扩展 express 的请求和响应接口的最佳做法是什么?如果可能,无需编写单独的 d.ts、在类型目录中操作任何内容或使用 /// <reference path="..." /> cmets。

【问题讨论】:

您可以让 tsc 使用定义标志为您的代码生成 d.ts 文件。你所要做的就是你的代码应该实现/扩展请求/响应接口/类 @toskv 如果我将 tsconfig.json 中的 declaration 设置为 true,tsc 会抱怨 exports = function 语句,因为它是“使用私有名称 'Express.Request'”,即使我在此处将 <reference> 添加到 express.d.ts 文件中。编译后(使用tsctsc -w 观察变化),有main.d.ts,但由于上述原因,middleware.d.ts 丢失了。并且 main.ts 仍在抱怨缺少 req.foobar ... 这听起来更像你不应该能够扩展 express.request 因为它被定义为私有。 :( 但是现有快速中间件的类型(以express-session 为例)可以正常工作。我使用tsc install express-session --save 调查了它是如何工作的。它添加了对 typings/tsd.d.ts 的引用,但是一旦我删除了该引用,它就再也找不到 req.session 了。而且我不想自己修改 tsd.d.ts,因为下一个 tsd 命令可能会删除我的硬编码引用。 你不应该有,难道你没有 tsconfig.json 和 package.json 文件来管理依赖关系吗? 【参考方案1】:

我自己找到了一个解决方案,使用this example 作为参考。我的中间件需要包装在一个声明的模块中,所以 middleware/foobar.ts 看起来像这样:

declare module Express 
  export interface Request 
    foobar?: string;
  


declare module 'foobar' 
  function foobar(req: Express.Request, res, next) 
    req.foobar = 'FooBar';
    next();
  

  export = foobar;

如果您在中间件中使用类或其他导入的东西,那就更麻烦了。在我的示例中,我的中间件使用我自己的“EntityManager”类,它是数据库连接的抽象(对我来说是 mysql)。我的中间件(对我来说是 middleware/database.ts)现在看起来像这样:

declare module Express 
  import  Manager as EntityManager  from 'entity-manager';

  export interface Request 
    entityManager?: EntityManager;
  


declare module 'database' 
  import * as mysql from 'mysql';
  import  Manager as EntityManager  from 'entity-manager';

  /* some middleware-related code */
  var pool = mysql.createPool(...);
  var entityManager = new EntityManager(pool);
  /* *** */


  /* the actual exported function */
  function database(req: Express.Request, res, next) 
    req.entityManager = entityManager;
    next();
  ;

  export = database;

请注意,我的 EntityManager 类被导入两次,每个模块声明一次。仅在两个模块上方导入它似乎不起作用。

更新

在声明的模块中包含实际代码(在我的例子中为'database')在 JS 文件中不会产生任何输出。

在常规模块中包含该代码要求名称不包含撇号(例如,其中不允许使用连字符)并且也不会产生单功能导出代码。

使实际代码完全脱离模块(因此只有声明的 Express 模块和扩展请求)会生成正确的 JS,但我的文本编辑器在 req 中找不到 entityManager

似乎我需要将类型(例如我自己对 Express.Request 的扩展)放入一个专用的 d.ts 文件中,其中不存在实际代码。

【讨论】:

找到合适的解决方案了吗? 至少我不太明白你在“更新”中写的东西..

以上是关于express:项目本地中间件扩展 Express.Request的主要内容,如果未能解决你的问题,请参考以下文章

express框架学习

使用 TypeScript 扩展 Express Request 对象

vue+express上传头像到数据库中img的路径

Express项目创建以及其路由介绍

Express项目创建以及其路由介绍

Express项目创建以及其路由介绍