node.js express,一个很奇怪的行为
Posted
技术标签:
【中文标题】node.js express,一个很奇怪的行为【英文标题】:node.js express, a very strange behaviour 【发布时间】:2017-12-12 10:11:20 【问题描述】:我有一个 Express 服务器正在运行。
我所做的是从 html 上传一个 Excel 文件,然后 Express 解析该文件并进行一些计算。
在 Excel 文件中,每一行都有用户地址的信息。
对于每个地址,我们的 Express 服务器将使用谷歌地图地理编码 API 来计算纬度和经度。
但是,由于 Google 每秒不接受超过 50 次对其地理编码 API 的请求,所以我必须使用 settimeout 来延迟计算。
例如,如果 Excel 文件有 50 个地址,那么我必须对每个地址使用 settimeout 以避免该速率限制。
这是我使用 settimeout 计算纬度、经度的代码
createFromFile(req, res)
var form = new formidable.IncomingForm();
return form.parse(req, function (err, fields, files)
if (err)
return res.status(500).json(error: err.message)
var workbook = new exceljs.Workbook();
return workbook.xlsx.readFile(files.excelfile.path).then(function()
// use workbook
var worksheet = workbook.getWorksheet(1)
var data = []
for (var i=2; i<=worksheet.rowCount; i++)
data.push(
from_name: worksheet.getCell('A'+i).value + '',
from_address: worksheet.getCell('B'+i).value + '',
from_phone: worksheet.getCell('C'+i).value + '',
receiver_name: worksheet.getCell('D'+i).value + '',
receiver_address: worksheet.getCell('E'+i).value + '',
receiver_phone: worksheet.getCell('F'+i).value + '',
note: worksheet.getCell('H'+i).value + ''
)
var delay = function(t)
return new Promise(function(resolve)
setTimeout(resolve, t)
)
return Promise.all(data.map(function(item, i)
return function()
return delay(750*i).then(function()
winston.log('debug', 'process for item '+i)
return geocoder.geocode(item.from_address).then(function(geo_data)
data[i].from_coord =
lat: geo_data[0].latitude,
lng: geo_data[0].longitude
return geocoder.geocode(item.receiver_address).then(function(geo_data)
data[i].receiver_coord =
lat: geo_data[0].latitude,
lng: geo_data[0].longitude
)
)
.catch(function(geo_error)
winston.log('error', 'geo_error', error: geo_error)
throw new Error('Address in line ' + i + ' is not valid')
)
)
()
))
.then(function()
winston.log('debug', 'we are done calculating location')
return res.status(201).json(data)
)
)
.catch(function(e)
winston.log('error', 'an error occurred')
return res.status(500).json(error: e.message)
)
)
下面是我调用 Express API 的代码,我使用 React 来做前端工作并使用 javascript fetch api 来请求服务器。
startUploadFile()
this.props.showLoader()
let data = new FormData()
data.append('excelfile', this.state.selectedFile)
data.append('name', 'excelfile')
var me = this
fetch(Const.restServer + '/create-from-file',
headers:
'Access-Token': this.props.access_token,
,
method: 'POST',
body: data
)
.then(function(r)
return r.json()
)
.then(function(r)
if (r.hasOwnProperty('error'))
throw new Error(r.error)
me.props.hideLoader()
me.props.showDialog('success', 'Process Complete')
)
.catch(function(e)
console.log(e)
me.props.hideLoader()
me.props.showDialog('error', e.message)
)
我的问题是当我使用上述代码在浏览器上上传文件时,我在快速日志文件中看到两个请求。像这样的:
我也会在这里提供我的代码来记录每个请求的信息
app.use(function(req, res, next)
winston.log('debug', 'call api:',
api: req.url, requestMethod: req.method
)
res.header("Access-Control-Allow-Origin", "*");
res.header(
"Access-Control-Allow-Headers",
"Origin, X-Requested-With, Content-Type, Accept, Access-Token, Web-Admin-Request"
);
next()
);
function isAuthenticated(req, res, next)
/**
** Rest API Middleware check if access_token is valid
*/
let accessToken = req.body.accessToken || req.get('Access-Token')
// bunch of codes to check accessToken
next()
app.post('/order/create-from-file', isAuthenticated, orderController.createFromFile);
我不明白为什么会这样。如果我使用 Postman 并选择文件并上传,它工作正常 - 日志中只有一个请求。
谁能告诉我是什么原因。我觉得这是 Express 的错误。我的 Express 版本是 4.15.2
【问题讨论】:
您可能想使用***.com/posts/44982171/edit 来编辑/更新您的问题,并在浏览器开发工具中添加网络窗格显示的日志。如果这表明浏览器实际上实际上发送了两次 POST 请求,那么这不会是 Express 中的错误。另一方面,如果这没有显示浏览器发送了两次,而是 Express 以某种方式处理了浏览器实际上没有发送的第二个 POST 请求,那么是的,这显然是 Express 中的一个错误 您是否有可能看到两个 POST 请求,因为第一个来自您的startUploadFile()
函数,第二个是默认表单帖子(由您从和调用 startUploadFile()
的同一个按钮触发由浏览器自动执行)?如果是这样,您需要阻止按钮的默认操作。如果这可能是错误,我们可以通过查看上传的 HTML 以及如何调用 startUploadFile()
来更具体地提供帮助。
@jfriend00 谢谢,但我不使用表单中的按钮,我只是在其上声明一个按钮和一个点击处理程序。 startUploadFile() 是点击处理程序。而且因为我的 api 服务器与这个 HTML 页面有不同的域名,如果表单自动提交它也无法到达我的 api 服务器。
你确定startUploadFile()
被调用一次还是两次?
@sideshowbarker 在我的 chrome 网络监控工具中,有 2 个请求,但第一个是 OPTIONS 请求,第二个是真正的 POST 请求。没有任何其他 POST 请求。
【参考方案1】:
您的代码添加到请求中的 Access-Token
请求标头会触发浏览器在尝试 POST
请求之前发送 CORS 预检 OPTIONS
请求。
https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS#Preflighted_requests 提供了更多细节,但要点是,只要您的代码将 Access-Token
标头添加到请求中,您就无法阻止浏览器进行额外的预检 OPTIONS
请求,因为它是作为 CORS 协议的一部分,浏览器会自动执行的操作。
使用 Postman 时看不到额外请求的原因是它不执行 CORS 预检 OPTIONS
请求 - 只有浏览器发送它,并且仅适用于 XHR/Fetch 从前端 JavaScript 代码发出的请求在特定来源的浏览器中运行(Postman 不是)。
【讨论】:
我知道 OPTIONS 请求,但我不明白的是第二个 POST 请求。请仔细看我附上的截图,你会看到第二个 POST 请求。我不明白它为什么会出现,因为我只调用了一次 startUploadFile()。 第二个 POST 请求与第一个重叠。所以在我的例子中,有两个进程在做这项工作。【参考方案2】:好吧,最后我可以通过将“Access-Token”传递到请求正文而不是请求标头来解决这个问题(现在,我的服务器总是只接收一个请求)。感谢@sideshowbarker,因为您的评论促使我采用这种方法。
我仍然认为这个问题是Express中的一个错误,但是因为它没有发生在我本地的开发环境中,所以我不会向他们发送报告。
【讨论】:
以上是关于node.js express,一个很奇怪的行为的主要内容,如果未能解决你的问题,请参考以下文章
SQL - node.js express - 反应加载行为
Image Magick Module 抛出奇怪的错误(Express js Node js)