AngularJS和ExpressJS会话pipe理?
我想保持整个页面的会话。 对于这个项目,我使用expresJs,nodeJS作为服务器端。 AngularJS在前端。
我不确定,当查看更改或URL更改时如何处理会话。 因为我需要照顾expresJS路由器或者angularJs路由器 。
请让我知道,我应该遵循什么方法。
angularJS路由器
myApp.config(['$routeProvider', function($routeProvider) { $routeProvider.when('/welcome', {templateUrl: 'partials/welcome.html', controller: 'MyCtrl2'}); $routeProvider.when('/login', {templateUrl: 'partials/login.html', controller: 'MyCtrl2'}); $routeProvider.when('/signup', {templateUrl: 'partials/signup.html', controller: 'singupController'}); $routeProvider.otherwise({redirectTo: '/'}); }]);
注册控制器
myApp.controller('singupController',function($scope,$rootScope,$http){ $scope.doSingnup = function() { var formData = { 'username' : this.username, 'password' : this.password, 'email' : null }; var jdata = JSON.stringify(formData); $http({method:'POST',url:'/signup',data:jdata}) .success(function(data,status,headers,config){ console.log(data); }). error(function(data,status,headers,config){ console.log(data) }); } })
ExpressJS路由器
module.exports = exports = function(app, db) { var sessionHandler = new SessionHandler(db); var contentHandler = new ContentHandler(db); // Middleware to see if a user is logged in app.use(sessionHandler.isLoggedInMiddleware); app.get('/', contentHandler.displayMainPage); app.post('/login', sessionHandler.handleLoginRequest); app.get('/logout', sessionHandler.displayLogoutPage); app.get("/welcome", sessionHandler.displayWelcomePage); app.post('/signup', sessionHandler.handleSignup); app.get('*', contentHandler.displayMainPage); // Error handling middleware app.use(ErrorHandler); }
注册后,我想redirect到login页面。 我怎么能在上面的路由器。 我应该使用以下哪一个来更改应用程序的视图1)angularJS的$位置2)ExpresJS的redirect
谢谢大家
所以我有同样的问题,公平的,我可能已经读了一个地方,我不记得了。
问题 :Angular构build单页面应用程序。 刷新之后,您将取消范围并使用经过身份validation的用户。
途径
AngularJS模块提供了一个称为run的启动函数,它在加载页面时总是被调用。 完美刷新/重新加载。
myApp.run(function ($rootScope, $location, myFactory) { $http.get('/confirm-login') .success(function (user) { if (user && user.userId) { $rootScope.user = user; } }); }
快递会话会为您保存会话,并使用您的浏览器发送的会话身份validation您的身份。 所以它总是知道你是否被authentication。
router.get('/confirm-login', function (req, res) { res.send(req.user) } );
我所要做的只是刷新后,所有的依赖被加载,问我是否通过身份validation,并设置$ rootScope.user = authenticatedUserFromExpress;
这里有两个不同的概念 – 服务器端会话状态和Angular客户端的用户状态。 在express中,您可以通过req.session使用会话来pipe理基于会话的数据。
在angular度方面,你的控制器只有一个范围。 如果要跟踪多个控制器上的某些数据,则需要创build一个服务来存储数据,并将服务注入到所需的控制器中。
典型的生命周期是首先检查服务中是否有数据,如果是这样的话。 如果没有,等待数据填充(由用户或应用程序或其他),然后检测这些变化,并与您的服务同步。
注册控制器
function SignupCtrl($scope, $http, $location) { $scope.form = {}; // to capture data in form $scope.errorMessage = ''; // to display error msg if have any $scope.submitPost = function() { // this is to submit your form can't do on //traditional way because it against angularjs SPA $http.post('/signup', $scope.form). success(function(data) { // if success then redirect to "/" status code 200 $location.path('/'); }).error(function(err) { // if error display error message status code 400 // the form can't be submitted until get the status code 200 $scope.errorMessage = err; }); }; }
sessionHandler.handleSignup
this.handleSignup = function(req, res, next) { "use strict"; // if you have a validate function pass the data from your // Signup controller to the function in my case is validateSignup // req.body is what you need validateSignup(req.body, function(error, data) { if(error) { res.send(400, error.message); // if error send error message to angularjs }else { // do something else // rmb to res.send(200) } }); }
validatesignup
function validateSignup(data,callback) { "use strict"; // the data is req.body //so now you can access your data on your form // eg you have 2 fields name="password" and name="confirmPassword on your form" var pass = data.password, comPass = data.confirmPassword; if(pass != comPass){ callback(new Error('Password must match'), null); // then show the error msg on the form by using //angular ng-if like <div ng-if="errorMessage">{{errorMessage}}</div> }else{ callback(null, data); } }
希望这个帮助
在这里的所有答案中,我最喜欢@ alknows的方法。 但是,像其他答案一样,您向服务器发送请求以获取当前的用户数据,我遇到了一些问题:
- 由于您的AJAX($ http)调用,您必须处理竞争条件。
- 您在向服务器发送不必要的请求之后,它已经呈现您的index.html
我尝试了@alknow的方法,在解决了由于我的angular度应用程序控制器和configuration需要当前用户执行他们的工作而导致的许多竞争条件之后,我find了解决scheme。 在适当的时候,我尽我所能避免出现竞争状况,所以我有点不情愿继续这种做法。 所以我想到了一个更好的方法:使用index.html将当前用户数据向下发送,并将其存储在本地。
我的方法:将currentUserembedded到客户端的index.html&本地存储
在你的服务器上的index.html
,制作一个脚本标记来保存你想传递给客户端的任何数据:
“`
<!--YOUR OTHER index.html stuff go above here--> <script id="server-side-rendered-client-data" type="text/javascript"> var __ssr__CData = { currentUser: { id: '12345', username: 'coolguy', etc: 'etc.' } } </script>
“`
然后,按照@alknows的build议,在app.js
或任何你启动你的angular度的应用程序,添加app.run(..., () => {...})
。 在app.run()中,您将需要获取服务器端呈现的客户端数据对象,我将其__ssr_CData
命名为__ssr_CData
这样我就不太可能在后面的其他javascript中碰到跨全局名称空间的名称冲突:
var myAngularApp = angular.module("mainApp", ['ngRoute']); myAngularApp.run(function ($rootScope) { const currentUserFromServer = __ssr__CData.currentUser const currentUserAccessTokenFromServer = __ssr__CData.accessToken const currentUser = CurrentUser.set(currentUserAccessTokenFromServer, currentUserFromServer) $rootScope.currentUser = currentUser });
如你所知, app.run()
将在页面完成重新加载时被调用。 CurrentUser
是一个在单页面环境中pipe理angular度应用程序当前用户的全局类。 因此,当我调用CurrentUser.set(...)
它将当前用户数据存储在稍后可以通过调用CurrentUser.get()
在angular度应用程序中检索的位置。 所以,在你的任何angular度的应用程序控制器,你现在可以检索当前用户服务器提供的只是这样做:
myAngularApp.controller('loginController',function($scope, $rootScope, $http){ //check if the user is already logged in: var currentUser = CurrentUser.get() if(currentUser) { alert("HEY! You're already logged in as " +currentUser.username) return $window.location.href = "/"; } //there is no current user, so let user log in //... }
在这个例子中,我使用CurrentUser.get()
(我在上面解释过)从服务器获取之前存储的当前用户。 我也可以通过访问$rootScope.currentUser
检索当前用户,因为我也存储在那里。 随你便。
myAngularApp.controller('signupController',function($scope, $rootScope, $http){ //check if the user is already logged in: var currentUser = CurrentUser.get() if(currentUser) { alert("HEY! You're already logged in as " +currentUser.username) return $window.location.href = "/"; } //there is no current user, so let user signup //... you run your signup code after getting form data $http({method:'POST',url:'/signup',data:jdata}) .success(function(data,status,headers,config){ //signup succeeded! //set the current user locally just like in app.js CurrentUser.set(data.newUser) //send user to profile return $window.location.href = "/profile"; }) .error(function(data,status,headers,config){ //something went wrong console.log(data) }); }
现在,在新用户注册后,您的服务器将从AJAX调用中返回新用户。 我们通过调用CurrentUser.set(...)
将该新用户设置为当前用户并将用户发送到他们的configuration文件。 现在,您可以像查看当前用户是否存在于login和注册控制器中那样获取configuration文件控制器中的当前用户。
我希望这可以帮助任何遇到此问题的人。 为了供您参考,我正在使用客户端会话模块来处理服务器上的会话。