Node/Express中MapQuest API调用遇'body used already'错误排查
问题描述
使用MapQuest API结合node-geocoder实现地理编码时,首次Postman请求成功,但后续所有请求均失败,报错:
HttpError: body used already for: https://www.mapquestapi.com/geocoding/v1/address?key=
相关代码如下:
geoCoder.js 配置
const NodeGeocoder = require('node-geocoder'); const options = { provider: process.env.GEOCODER_PROVIDER, // fetch: customFetchImplementation, httpAdapter: 'https', apiKey: process.env.GEOCODER_API_KEY, formatter: null }; const geocoder = NodeGeocoder(options); module.exports = geocoder
Mongoose HomeSchema
const mongoose = require('mongoose') const geocoder = require('../utils/geocoder') const HomeSchema = new mongoose.Schema({ homeId: { type: String, required: [true, 'Please add a home ID'], unique: true, trim: true, maxlength: [10, 'Home ID must be less than 10 characters'] }, address: { type: String, required: [true, 'Please add an address'] }, location: { type: { type: String, enum: ['Point'], }, coordinates: { type: [Number], index: '2dsphere' }, formattedAddress: String }, createdAt: { type: Date, default: Date.now } }) // Geocode & create location HomeSchema.pre('save', async function(next) { const loc = await geocoder.geocode(this.address) // console.log(loc) this.location = { type: 'Point', coordinates: [loc[0].longitude, loc[0].latitude], formattedAddress: loc[0].formattedAddress } // Do not save address this.address = undefined next() }) module.exports = mongoose.model('Home', HomeSchema)
请求处理控制器
exports.addHome = async (req, res, next) => { try { // console.log(req.body) const home = await Home.create(req.body) return res.status(201).json({ success: true, data: home }) } catch (error) { console.error(error) if(error.code === 11000) { return res.status(400).json({ error: 'This home already exists.'}) } res.status(500).json({error: 'Server error here!'}) } }
原因分析
这个错误本质是请求体被重复读取导致的。node-geocoder默认的HTTP请求实现会复用请求对象,而HTTP请求体只能被消费一次。当单例的geocoder实例被多次调用时,之前的请求对象被重复使用,就会触发body used already错误。
解决方案
方案1:自定义fetch实现,避免请求对象复用
安装node-fetch依赖:
npm install node-fetch
修改geoCoder.js,添加自定义fetch逻辑,确保每次请求都创建独立的请求配置:
const NodeGeocoder = require('node-geocoder'); const fetch = require('node-fetch'); const options = { provider: process.env.GEOCODER_PROVIDER, // 自定义fetch,每次请求传递全新的配置对象 fetch: (url, opts) => fetch(url, { ...opts }), httpAdapter: 'https', apiKey: process.env.GEOCODER_API_KEY, formatter: null }; const geocoder = NodeGeocoder(options); module.exports = geocoder;
方案2:升级node-geocoder到最新版本
该问题可能是旧版本node-geocoder的bug,升级到最新版本大概率能解决:
npm update node-geocoder
方案3:临时方案——每次请求创建新的geocoder实例(不推荐,影响性能)
如果上述方案无效,可以在pre('save')钩子中每次创建新的geocoder实例,避免单例复用:
// 修改HomeSchema中的pre钩子 HomeSchema.pre('save', async function(next) { const NodeGeocoder = require('node-geocoder'); const geocoder = NodeGeocoder({ provider: process.env.GEOCODER_PROVIDER, httpAdapter: 'https', apiKey: process.env.GEOCODER_API_KEY, formatter: null }); const loc = await geocoder.geocode(this.address) this.location = { type: 'Point', coordinates: [loc[0].longitude, loc[0].latitude], formattedAddress: loc[0].formattedAddress } this.address = undefined next() })
内容的提问来源于stack exchange,提问作者aquile hollins
相关产品推荐
相关产品推荐

