用于动态路由的路由装饰器,允许斜线作为变量字符串的一部分

Route decorator for dynamic routing allowing a slash as part of the varible string

我有一个 loopback4 控制器来在服务器上获取和创建一些文件。所有文件都存储在具有更深目录的目录结构中。它可能看起来像这样:

├── WA2114
│   ├── 300dpi
│   │   ├── WA2114_Frontal.jpg
│   │   └── WA2114_entnehmen.jpg
│   ├── web
│   │   ├── WA2114-anwendung-Aufbewahrung.jpg
│   │   └── WA2114_Verpackung_NEU.jpg
│   ├── Produktdatenblatt
│   │   └── 2114-000.pdf

我想要一个方法,根据调用的 RestAPI 路由获取所有文件:

GET /files/{category}

如果我调用 GET /files/WA2114,我想获取位于 WA2114/ 下的所有文件的列表。如果我调用 GET /files/WA2114/300dpi 我只想要更深文件夹中的文件../300dpi。我希望很清楚,目标是什么。 通过POST /files/{category}上传新文件需要相同的逻辑。

我已经尝试过此处描述的解决方案:https://lideo.github.io/loopback.io/doc/en/lb4/Routes.html 但没有成功。

我已经为顶级目录设置了路由。但是更深的目录无法动态访问,因为路由装饰器似乎粘在了级别上并且变量中不允许使用斜线。我不想创建许多方法来处理每个目录级别。

我当前的控制器(简体):

export class FileController
{
    constructor(@repository(FileRepository) public fileRepository: FileRepository)
    {
    }

    @get('/files/{category}', {
        responses: {
            '200': {
                description: 'Array of File model instances of the specified category',
                content:     {
                    'application/json': {
                        schema: {type: 'array', items: {'x-ts-type': File}}
                    }
                }
            }
        }
    })
    async findbyCategory(@param.path.string('category') category: string): Promise<File[]>
    {
        return await this.fileRepository.findByCategory(category);
    }
}

我如何修饰控制器方法才能使用相同的方法动态获取 /files/a 和 files/a/b/c?

我已经在 php/Symphony 中做过类似的事情,看起来像这样: @Route("/files/{category}", methods={"GET"}, requirements={"category"=".+"}).+ 是这里的魔法。现在我必须用 loopback4 重建代码并且必须重构路由,而我在这一个上失败了。有人对此有解决方案吗?

I have already set up a route for the top directory. But the deeper directories are not reachable dynamically because the route decorator seems to be sticked on the level and slashes are not allowed in the variable. I don't want to create dozens of methods to handle every directory level.

  • App会在sequence.ts处理您的请求,并根据您的请求地址、参数等找到对应的路由器

export class MySequence implements SequenceHandler {
    constructor(
        @inject(SequenceActions.FIND_ROUTE) protected findRoute: FindRoute,
        @inject(SequenceActions.PARSE_PARAMS) protected parseParams: ParseParams,
        @inject(SequenceActions.INVOKE_METHOD) protected invoke: InvokeMethod,
        @inject(SequenceActions.SEND) public send: Send,
        @inject(SequenceActions.REJECT) public reject: Reject,
    ) { }

    async handle(context: RequestContext) {
        try {
            const { request, response } = context;
            const route = this.findRoute(request); // <= here!!! find router by request
            const args = await this.parseParams(request, route);
            const result = await this.invoke(route, args);
            this.send(response, result);
        } catch (err) {
            this.reject(context, err);
        }
    }
}

  • 您需要 "cheat" FindRoute 并将以下请求分配给同一路由器

假设:

我们有一个控制器A,其中一个api是@get("/api/{category}")

之前:

/api/dir-1 => url=/api 参数=dir-1 => 控制器A

/api/dir-1/file-2 => url=/api/dir-1 param=file-2 => (找不到控制器)

/api/dir-1/dir-2/file-3 => url=/api/dir-1/dir-2 param=file-3 => (找不到控制器)

    async handle(context: RequestContext) {
        try {
            const { request, response } = context;

            // !
            if (
                request.method === "GET" && request.url === "/api/"
            ) {
                request.url = `/files/'${request.url.slice(7).replace(/\//gi, '----')}'`;
            }

            const route = this.findRoute(request);
            const args = await this.parseParams(request, route);
            const result = await this.invoke(route, args);
            this.send(response, result);
        } catch (err) {
            this.reject(context, err);
        }
    }

之后:

/api/dir-1 => url=/api 参数=dir-1 => 控制器A

/api/dir-1/file-2 => url=/api 参数=dir-1----file-2 => 控制器A

/api/dir-1/dir-2/file-3 => url=/api 参数=dir-1----dir-2----file-3 => 控制器A

  • 完成,现在您可以在控制器中处理文件A。但我认为这不是一个好的解决方案,你需要新建一个FindRoute并将相应的逻辑放在里面。

详情请看我的example project