简体   繁体   中英

node.js express, a very strange behaviour

I have an Express server running.

What i do is upload an Excel File from HTML and then Express parse that file and do some calculating.

In the Excel file, each row has information about address of a User.

For each Address, our Express server will use google map geocoding API to calculate the latitude & longitude.

But, because Google doesn't accept more than 50 request per second to their geocoding API, so i have to use settimeout to delay the calculating.

For example if the Excel file has 50 addresses, so i have to use settimeout on each address to avoid that rate limit.

Here is my code to use settimeout and calculate latitude, longitude

 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}) }) }) } 

And below is my codes to call that Express API, i used React to do frontend job & used javascript fetch api to request to server.

 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) }) } 

My problem is when i used above codes to uploading a file on browser, i see two request in express log file. Something like this:

Express Server日志文件 I will provide my codes to log info of every request here too

 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); 

I don't understand why this happen. If I use Postman & select a File & upload, it works fine - just only One Request in logs.

Can anyone tell me what is the reason. I feel like this is a Bug of Express. My Express version is 4.15.2

The Access-Token request header your code adds to the request triggers browsers to send a CORS preflight OPTIONS request before trying the POST request.

https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS#Preflighted_requests gives more detail but the gist of it is, as long as your code's adding that Access-Token header to the request, there's no way you can prevent browsers from making the extra preflight OPTIONS request—because it's something browsers do automatically as part of the CORS protocol.

The reason you don't see the extra request when you use Postman is that it doesn't do the CORS preflight OPTIONS request—only browsers send it, and only for requests made by XHR/Fetch from frontend JavaScript code running in a browser at a specific origin (which Postman isn't).

Well, finally i can fix this problem by passing 'Access-Token' into request body instead of request header (now, my server always receive only one request). Thank to @sideshowbarker because your comment trigger me to do this method.

I still think this Problem is a bug in Express, but because it didn't occur on my local development environment, so i will not send a report to them.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM