我正在运行Express服务器。
我所做的是从HTML上传Excel文件,然后Express解析该文件并进行一些计算。
在Excel文件中,每一行都包含有关用户地址的信息。
对于每个地址,我们的Express服务器将使用谷歌地图地理编码API来计算纬度和数据。经度。
但是,由于Google每秒对其地理编码API不接受超过50个请求,因此我必须使用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做前端工作&amp;使用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&amp;选择一个文件&amp;上传,它工作正常 - 日志中只有一个请求。
谁能告诉我是什么原因。我觉得这是一个快递的Bug。我的快递版本是4.15.2
答案 0 :(得分:2)
您的代码添加到请求的Access-Token
请求标头会在尝试OPTIONS
请求之前触发浏览器发送CORS预检POST
请求。
https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS#Preflighted_requests提供了更多详细信息,但其中的要点是,只要您的代码将Access-Token
标头添加到请求中,就无法阻止浏览器进行额外的预检{{1请求 - 因为它是浏览器自动作为CORS协议的一部分。
当您使用Postman时没有看到额外请求的原因是它不执行CORS预检OPTIONS
仅请求的浏览器发送它,并且仅针对XHR / Fetch从前端发出的请求在特定来源的浏览器中运行的JavaScript代码(Postman不是)。
答案 1 :(得分:1)
好吧,最后我可以通过将'Access-Token'传递给请求主体而不是请求头来解决这个问题(现在,我的服务器总是只收到一个请求)。感谢@sideshowbarker,因为您的评论会触发我执行此方法。
我仍然认为这个问题是Express中的一个错误,但因为它没有在我的本地开发环境中发生,所以我不会向他们发送报告。