使用Prisma实现分页等功能时出现Route.get()回调错误求助
问题:Express路由报错,Prisma实现分页功能失败
错误信息
Error: Route.get() requires a callback function but got a [object Promise] at Route.<computed> [as get] (C:\Users\malay jeena\Documents\CODE\Web development\15_Pagination\pagination_v2\node_modules\express\lib\router\route.js:211:15) at app.<computed> [as get] (C:\Users\malay jeena\Documents\CODE\Web development\15_Pagination\pagination_v2\node_modules\express\lib\application.js:499:19) at Object.<anonymous> (C:\Users\malay jeena\Documents\CODE\Web development\15_Pagination\pagination_v2\app.js:66:5)
使用Prisma实现分页、搜索、排序、过滤功能时触发上述错误,保存文件后立即出现。此前用Mongoose实现相同功能无异常,已完成Prisma schema创建、迁移等基础操作,附上完整代码求解决,同时排查后续可能的TypeError。
相关代码
app.js 文件
require('dotenv').config(); const express = require('express'); const { PrismaClient } = require('@prisma/client'); const prisma = new PrismaClient(); const userController = require('./controller/userController'); const app = express(); (async () => { try { await prisma.$connect(); console.log('Connected to the database'); createTestData(); } catch (error) { console.error('Error connecting to the database:', error); } })(); const usersData = [ { firstname: 'John', lastname: 'Doe', email: 'johndoe1@example.com', age: 25 }, { firstname: 'Jane', lastname: 'Doe', email: 'janedoe2@example.com', age: 30 }, { firstname: 'Alice', lastname: 'Brown', email: 'alicebrown3@example.com', age: 28 }, { firstname: 'Bob', lastname: 'Smith', email: 'bobsmith4@example.com', age: 35 }, { firstname: 'Charlie', lastname: 'Johnson', email: 'charliejohnson5@example.com', age: 40 }, { firstname: 'David', lastname: 'Williams', email: 'davidwilliams6@example.com', age: 45 }, { firstname: 'Eve', lastname: 'Jones', email: 'evejones7@example.com', age: 50 }, { firstname: 'Frank', lastname: 'Taylor', email: 'franktaylor8@example.com', age: 55 }, { firstname: 'Grace', lastname: 'Lee', email: 'gracelee9@example.com', age: 60 }, { firstname: 'Hank', lastname: 'Harris', email: 'hankharris10@example.com', age: 65 }, { firstname: 'Irene', lastname: 'Clark', email: 'ireneclark11@example.com', age: 70 }, { firstname: 'Jack', lastname: 'Lewis', email: 'jacklewis12@example.com', age: 75 }, { firstname: 'Kate', lastname: 'Young', email: 'kateyoung13@example.com', age: 80 }, { firstname: 'Larry', lastname: 'Hall', email: 'larryhall14@example.com', age: 85 }, { firstname: 'Mary', lastname: 'Allen', email: 'maryallen15@example.com', age: 90 } ]; const createTestData = async () => { try { const userCount = await prisma.user.count(); if (userCount === 0) { await prisma.user.createMany({ data: usersData.map(user => ({ firstName: user.firstname, lastName: user.lastname, email: user.email, age: user.age, })), }); console.log('Test data created successfully'); } else { console.log('Test data already exists'); } } catch (error) { console.error('Error creating test data:', error); } }; app.get('/users', userController.getUsers, userController.getAllUsers); app.listen(3000, () => { console.log("Server is running on port 3000"); });
pagination.js 文件
const { PrismaClient } = require('@prisma/client'); const prisma = new PrismaClient(); async function getUsersWithPagination(modelName) { return async (req, res, next) => { const page = parseInt(req.query.page) || 1; const limit = parseInt(req.query.limit) || 5; const search = req.query.search || ""; const sortBy = req.query.sortBy || 'firstname'; const sortOrder = parseInt(req.query.sortOrder) || 1; const filterBy = req.query.filterBy ? req.query.filterBy.split(',') : []; const filterValue = req.query.filterValue || ''; const startIndex = (page - 1) * limit; const endIndex = page * limit; const results = {}; if (endIndex < await modelName.count()) { results.next = { page: page + 1, limit: limit }; } if (startIndex > 0) { results.previous = { page: page - 1, limit: limit }; } // Add search functionality const searchQuery = { OR: [ { firstname: { contains: search, mode: 'insensitive' } }, { lastname: { contains: search, mode: 'insensitive' } } ] }; // Add filtering functionality const filter = {}; if (filterBy.length > 1 && filterValue) { const filterConditions = filterBy.map(field => { return { [field]: { contains: filterValue, mode: 'insensitive' } }; }); filter.OR = filterConditions; } else if (filterBy && filterValue) { filter[filterBy] = isNaN(Number(filterValue)) ? filterValue : Number(filterValue); } // Add sorting functionality const orderBy = { [sortBy]: sortOrder === 1 ? 'asc' : 'desc' }; try { results.results = await modelName.findMany({ where: { ...searchQuery, ...filter }, orderBy, take: limit, skip: startIndex }); console.log(results); res.paginatedResults = results; res.next = results.next; res.previous = results.previous; res.users = results.results.length; next(); } catch (error) { res.status(500).json({ message: error.message }); } }; } module.exports = getUsersWithPagination;
userController.js 文件
const { PrismaClient } = require('@prisma/client'); const prisma = new PrismaClient(); const getUsersWithPagination = require('../util/pagination'); const getUsers = getUsersWithPagination(prisma.user); const getAllUsers = async (req, res) => { try { const users = res.paginatedResults.results || []; res.status(200).json({ status: 'success', results: res.users, next: res.next, previous: res.previous, data: { users } }); } catch (error) { res.status(400).json({ status: 'fail', message: error }); } }; module.exports = { getAllUsers, getUsers };
解决方案
1. 修复路由回调类型错误
核心问题是getUsersWithPagination被定义为async函数,导致它返回Promise而非Express中间件函数。Express路由需要普通函数作为回调,因此去掉外层async:
// pagination.js 中修改函数定义 function getUsersWithPagination(modelName) { return async (req, res, next) => { // 原有逻辑不变 }; }
2. 统一Prisma字段名
createTestData中用firstName/lastName(Prisma默认驼峰命名),但pagination.js中用firstname/lastname,会导致查询报错,统一为驼峰字段:
// pagination.js 中修改搜索和排序逻辑 const searchQuery = { OR: [ { firstName: { contains: search, mode: 'insensitive' } }, { lastName: { contains: search, mode: 'insensitive' } } ] }; const sortBy = req.query.sortBy || 'firstName';
3. 修复分页count的异常捕获
原代码中await modelName.count()未包裹在try块,失败会导致未捕获异常,将分页判断移到try块内:
// pagination.js 中修改try块内容 try { const totalCount = await modelName.count({ where: { ...searchQuery, ...filter } }); if (endIndex < totalCount) { results.next = { page: page + 1, limit: limit }; } if (startIndex > 0) { results.previous = { page: page - 1, limit: limit }; } results.results = await modelName.findMany({ where: { ...searchQuery, ...filter }, orderBy, take: limit, skip: startIndex }); // 后续赋值逻辑不变 } catch (error) { res.status(500).json({ message: error.message }); }
4. 修复过滤逻辑的字段处理
原代码中filterBy是数组,单个字段时直接用数组作为键名会出错,且数字字段(如age)不能用contains操作:
// pagination.js 中修改过滤逻辑 const filter = {}; if (filterBy.length > 0 && filterValue) { if (filterBy.length > 1) { const filterConditions = filterBy.map(field => { if (field === 'age' && !isNaN(Number(filterValue))) { return { [field]: { equals: Number(filterValue) } }; } return { [field]: { contains: filterValue, mode: 'insensitive' } }; }); filter.OR = filterConditions; } else { const field = filterBy[0]; if (field === 'age' && !isNaN(Number(filterValue))) { filter[field] = Number(filterValue); } else { filter[field] = { contains: filterValue, mode: 'insensitive' }; } } }
5. 复用Prisma实例
多个文件重复创建PrismaClient可能导致连接泄漏,新建prisma.js统一导出实例:
// prisma.js const { PrismaClient } = require('@prisma/client'); const prisma = new PrismaClient(); module.exports = prisma;
在app.js、pagination.js、userController.js中替换引入:
const prisma = require('./prisma');
后续验证
完成修改后启动服务器,测试以下场景:
- 基础分页:
http://localhost:3000/users - 搜索:
http://localhost:3000/users?search=John - 排序:
http://localhost:3000/users?sortBy=age&sortOrder=-1 - 过滤:
http://localhost:3000/users?filterBy=age&filterValue=25
内容的提问来源于stack exchange,提问作者Malay Jeena
相关产品推荐
相关产品推荐

