我有一个运行我的REST API的Node服务器。
我从我的 Angular 应用程序调用 API,但有时如果我只是停留在同一页面上,最后一个已知请求会多次执行。
我开始认为这只是我所在的页面的问题,但现在很长一段时间后,我发现无论我在应用程序中的哪个页面上,它都是如此。
我注意到,虽然在我的前端控制台 (Chrome) 中,调用没有多次执行。
我的API包含很多路由文件,但主要结构如下所示:
服务器.js
// BASE SETUP
// =============================================================================
var express = require('express'),
bodyParser = require('body-parser');
var app = express();
var router = express.Router();
var es = require('express-sequelize');
var multer = require('multer');
var Excel = require("exceljs");
var ex = require('xlsjs');
var stream = require('stream');
var fs = require('fs');
var XLSX = require('xlsx');
var async = require('async');
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({
extended: true
}));
// =============================================================================
//Secure
app.all('/*', function (req, res, next) {
// CORS headers
res.header("Access-Control-Allow-Origin", "*"); // restrict it to the required domain
res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,OPTIONS');
// Set custom headers for CORS
res.header('Access-Control-Allow-Headers', 'Content-type,Accept,X-Access-Token,X-Key');
if (req.method == 'OPTIONS') {
res.status(200).end();
} else {
next();
}
});
var env = app.get('local') == 'development' ? 'dev' : app.get('env');
var port = process.env.PORT || 8080;
var Sequelize = require('sequelize');
// db config
var env = "local";
var config = require('./database.json')[env];
var password = config.password ? config.password : null;
// initialize database connection
var sequelize = new Sequelize(
config.database,
config.user,
config.password,
{
port: config.port,
host: config.server,
logging: console.log,
define: {
timestamps: false
}
}
);
var user = {};
var done = {is_complete: false};
app.use(multer({
dest: './uploads/',
rename: function (fieldname, filename) {
return filename + Date.now();
},
onFileUploadStart: function (file) {
console.log(file.originalname + ' is starting ...')
},
onFileUploadComplete: function (file) {
//Redirects request to path
}
}));
var auth = require('./auth.js')(express, sequelize, router);
app.all('/api/*', [require('./middlewares/validateRequest')]);
app.use('/', router);
app.use(auth);
//Init models
var division_model = require('./lb_models/division/division_model')(express, sequelize, router, user, async);
var location_model = require('./lb_models/division/Location')(express, sequelize, router, user, async);
var user_model = require('./lb_models/user/user_model')(express, sequelize, router, user, async);
var title_model = require('./lb_models/title/Title')(express, sequelize, router, user, async);
var login_stat = require('./lb_models/user/Login')(express, sequelize, router, user, async);
var quote_model = require('./lb_models/Quote')(express, sequelize, router, user, async);
var organization_model = require('./lb_models/user/Organization')(express, sequelize, router, user, async);
var competence_model = require('./lb_models/competence/Competence')(express, sequelize, router, user, async, multer, done);
var competenceCategory_model = require('./lb_models/competence/CompetenceCategory')(express, sequelize, router, user, async, multer, done);
var level_model = require('./lb_models/competence/Level')(express, sequelize, router, user, async, multer, done);
/*
Admin dashboard
*/
var admin_dash = require('./lb_models/dashboard/AdminDashboard')(express, sequelize, router, user, async);
/*
Modules
*/
var category_model = require('./lb_models/module/Category')(express, sequelize, router, user, async);
var module_type = require('./lb_models/module/Type')(express, sequelize, router, user, async);
var module_model = require('./lb_models/module/Module')(express, sequelize, router, user, async);
var component_model = require('./lb_models/module/Component')(express, sequelize, router, user, async);
/*
Academy
*/
var academy_model = require('./lb_models/academy/Academy')(express, sequelize, router, user, async);
var academyModule_model = require('./lb_models/academy/AcademyModule')(express, sequelize, router, user, async);
var academy_team = require('./lb_models/academy/Team')(express, sequelize, router, user, async);
var academy_course_model = require('./lb_models/academy/AcademyCourse')(express, sequelize, router, user, async);
var user_academy_model = require('./lb_models/academy/UserAcademy')(express, sequelize, router, user, async);
/*
Stat
*/
var comp_stat = require('./lb_models/competence/CompetenceStat')(express, sequelize, router, user, async);
var userComp = require('./lb_models/competence/UserCompetence')(express, sequelize, router, user, async);
/*
Screening
*/
var screening_model = require('./lb_models/screening/Screening')(express, sequelize, router, user, async);
/*
Testview
*/
var answers = require('./lb_models/testview/Answer')(express, sequelize, router, user, async);
var medals = require('./lb_models/testview/Medal')(express, sequelize, router, user, async);
/*
Course
*/
var courses = require('./lb_models/course/Course')(express, sequelize, router, user);
var reasons = require('./lb_models/course/Reason')(express, sequelize, router, user);
/*
Material
*/
var material = require('./lb_models/material/Material')(express, sequelize, router, user);
var profileDocument = require('./lb_models/material/ProfileDocument')(express, sequelize, router, user);
/*
Activity
*/
var activities = require('./lb_models/activity/Activity')(express, sequelize, router, user);
/*
Analytics
*/
var activity_model = require('./lb_models/analytics/Activity')(express, sequelize, router, user, async);
var academyStat_model = require('./lb_models/analytics/Academy')(express, sequelize, router, user, async);
var teamStat_model = require('./lb_models/analytics/Team')(express, sequelize, router, user, async);
var academyReport_model = require('./lb_models/analytics/Report')(express, sequelize, router, user, async);
var analytics_user_model = require('./lb_models/analytics/User')(express, sequelize, router, user, async);
var analytics_overview = require('./lb_models/analytics/Overview')(express, sequelize, router, user, async);
var analytics_survey = require('./lb_models/analytics/Survey')(express, sequelize, router, user, async);
/*
Self development
*/
var selfDevelopment_model = require('./lb_models/analytics/SelfDevelopment')(express, sequelize, router, user, async);
/*
Benchmark
*/
var academyBenchmark_model = require('./lb_models/analytics/AcademyBenchmark')(express, sequelize, router, user, async);
/*
Jeopardy
*/
var jeopardy_model = require('./lb_models/jeopardy/jeopardy')(express, sequelize, router, user, async);
app.use(division_model);
app.use(location_model);
app.use(user_model);
app.use(title_model);
app.use(quote_model);
app.use(organization_model);
app.use(login_stat);
app.use(competence_model);
app.use(competenceCategory_model);
app.use(level_model);
/*
Admin Dashboard
*/
app.use(admin_dash);
/*
Modules
*/
app.use(category_model);
app.use(module_type);
app.use(module_model);
app.use(component_model);
/*
Academy
*/
app.use(academy_model);
app.use(academy_team);
app.use(academyModule_model);
app.use(academy_course_model);
app.use(user_academy_model);
/*
Screening
*/
app.use(screening_model);
/*
Stat
*/
app.use(comp_stat);
app.use(userComp);
/*
Testview
*/
app.use(answers);
app.use(medals);
/*
Course
*/
app.use(courses);
app.use(reasons);
/*
Material
*/
app.use(material);
app.use(profileDocument);
/*
Activity
*/
app.use(activities);
/*
Analytics
*/
app.use(activity_model);
app.use(academyStat_model);
app.use(teamStat_model);
app.use(academyReport_model);
app.use(analytics_user_model);
app.use(analytics_overview);
app.use(analytics_survey);
/*
Self development
*/
app.use(selfDevelopment_model);
/*
Benchmark
*/
app.use(academyBenchmark_model);
/*
Jeopardy
*/
app.use(jeopardy_model);
// If no route is matched by now, it must be a 404
app.use(function (req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});
// START THE SERVER
app.listen(port);
console.log('Magic happens on port ' + port);
为什么会这样?这是一个大问题,因为我的 create 语句会在我的数据库中创建多个项目。
其他信息
我尝试了一些东西。如果响应处于挂起状态(意味着我不返回响应),请求会再次运行吗?
这是我的猜测,尽管您的问题缺乏足够的细节来确定 - 如果响应超时,许多浏览器将自动重试 XHR 请求。他们将对应该幂等且可以安全重试的请求(包括 GET)执行此操作。当我延迟响应时,我会看到这一点,因为我有一个交互式调试器在断点上暂停服务器代码。如果您的快递响应速度不够快,angular 可能会重试请求,所以这可能是您注意到的。
请检查一下:
- 您已启用 CORS,因此,如果您执行需要 cors 的请求,则浏览器将首先执行 OPTIONS 请求,然后执行请求(获取、发布、放置或删除)。
似乎这是因为浏览器发出印前检查选项请求:
。"预检"请求首先通过选项发送 HTTP 请求 方法到另一个域上的资源,以便确定 发送实际请求是否安全。
因此,app.all
匹配所有请求方法,这就是执行双重代码的原因。
溶液:
我强烈建议您使用适当的语义指定请求方法。仅将 GET 用于获取数据(它不应更改服务器端的状态,POST - 仅用于更改服务器端的数据。否则,您的网站可能容易受到CSRF(请参阅"GET场景")攻击。
当我使用 app.all('*', ...
并通过 POST 方法请求时,同样的事情也发生在我身上。在我app.get()
和app.post()
分开后,它不再发生。
var router = function(res, req){
console.log(req.method);
};
// run twice
app.all('*', router);
// run once
app.get('*', router);
app.post('*', router);
- 版本 express@4.13.4