Express应用如何忽略空请求参数 仅使用传入的有效参数
问题场景
现有支持多参数筛选的商品查询API,示例:localhost:8000/api/v1/products?page=1&user=62831ebc8cecf3c829c4b2d9&category=62831ebc8cecf3c829c4b2d9
编写的React action代码如下:
export const listProducts = (page = '', user = '', category = '') => async (dispatch) => { try { dispatch({ type: PRODUCT_LIST_REQUEST }) const { data } = await axios.get( `${process.env.REACT_APP_API}/api/v1/products?&page=${page}&user=${user}&category=${category}` ) dispatch({ type: PRODUCT_LIST_SUCCESS, payload: data, }) } catch (error) { dispatch({ type: PRODUCT_LIST_FAIL, payload: error.response && error.response.data.message ? error.response.data.message : error.message, }) } }
遇到的问题
- 执行
dispatch(listProducts(1, user._id))、category参数留空时,接口返回Invalid category ''错误 - 将参数默认值从空字符串替换为
null后,返回Invalid category null错误 - 业务需要支持灵活传参:有时仅传category,有时仅传user和page,需要实现:
- 前端自动忽略未传入的空参数,仅拼接有效参数到请求URL
- Express后端自动忽略未发送的参数,仅使用传入的有效参数完成筛选
解决方案
前端修改
不要手动硬编码拼接所有查询参数,先过滤空值再交给axios自动处理参数拼接,避免无效参数被传到后端。
修改后的action代码:
export const listProducts = // 参数默认值设为undefined即可,不需要设为空字符串或者null (page = undefined, user = undefined, category = undefined) => async (dispatch) => { try { dispatch({ type: PRODUCT_LIST_REQUEST }) // 组装参数对象,过滤掉值为undefined、null、空字符串的无效项 const rawParams = { page, user, category } const validParams = Object.fromEntries( Object.entries(rawParams).filter(([_, value]) => { return value !== undefined && value !== null && value !== '' }) ) // 直接把有效参数传给axios的params配置项,由axios自动拼接查询字符串 const { data } = await axios.get( `${process.env.REACT_APP_API}/api/v1/products`, { params: validParams } ) dispatch({ type: PRODUCT_LIST_SUCCESS, payload: data, }) } catch (error) { dispatch({ type: PRODUCT_LIST_FAIL, payload: error.response && error.response.data.message ? error.response.data.message : error.message, }) } }
注意:原代码手动拼接URL时写了
?&page=,多了一个多余的&,交给axios处理params可以完全避免这类语法错误,同时axios会自动对参数做URL编码,兼容性更好。
后端(Express)修改
后端不要对所有查询参数强制做存在性校验,仅当参数实际被传入时,才做格式校验和加入筛选逻辑,示例代码:
const mongoose = require('mongoose') const Product = require('./models/product') // 替换为实际的Product模型路径 app.get('/api/v1/products', async (req, res) => { try { const filter = {} // 分页参数给默认值,没传的时候默认查第1页 const page = Number(req.query.page) || 1 const pageSize = 10 // 单页条数按业务需求调整 const { user, category } = req.query // user参数存在时才校验格式、加入筛选条件 if (user) { if (!mongoose.Types.ObjectId.isValid(user)) { return res.status(400).json({ message: 'Invalid user id' }) } filter.user = user } // category参数存在时才校验格式、加入筛选条件 if (category) { if (!mongoose.Types.ObjectId.isValid(category)) { return res.status(400).json({ message: 'Invalid category id' }) } filter.category = category } // 查询数据 const total = await Product.countDocuments(filter) const products = await Product.find(filter) .limit(pageSize) .skip((page - 1) * pageSize) res.json({ products, page, pages: Math.ceil(total / pageSize) }) } catch (error) { res.status(500).json({ message: error.message }) } })
修改后,不管前端传哪几个参数的组合,后端都能正常处理,不会因为缺少某个参数报格式错误。
内容的提问来源于stack exchange,提问作者merlin
相关产品推荐
相关产品推荐

