【发布时间】: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
【问题讨论】:
-
您可能想使用stackoverflow.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 请求。
标签: javascript node.js express cors fetch-api