【问题标题】:Express routes with same path but different parameters具有相同路径但不同参数的快速路由
【发布时间】:2022-04-07 13:40:14
【问题描述】:

我有两种方法:

  • validateRegistration(),调用app.get('/users/:email', todo)

  • login(),调用app.get('/users/:username', todo)

validateRegistration() 工作正常,但是当 login() 被调用时,它返回 null,但是如果我在 server.js 中注释掉 app.get('/users/:email', todo),login() 返回预期的反应。似乎两者在 server.js 中不能同时存在

见下方相关代码

registerPage.html

<div class="container" ng-show="show">
		<form name="registerForm" novalidate>

			<h2>Registration</h2>
			<span>All fields required</span>
			<br>
			<br>
			<label>First Name</label>
			<br>
			<input class="form-control" type="text" ng-model="user.fName" name="fName" required placeholder="First Name">
			<div ng-messages="registerForm.fName.$error">
				<div class="errorMsg" ng-message="required">Required</div>
			</div>
			
			<br>
			<label>Last Name</label>
			<input class="form-control" type="text" ng-model="user.lName" name="lName" required placeholder="Last Name">
			<div ng-messages="registerForm.lName.$error">
				<div class="errorMsg" ng-message="required">Required</div>
			</div>

			<br>
			<label>Email</label>
			<input class="form-control" ng-model="user.email" ng-change="validateEmail(user.email)" type="email" name="emailAdd" required placeholder="Email">
			<span class="errorMsg">{{emailExistsMsg}}</span>

			<div ng-messages="registerForm.emailAdd.$error">
				<div class="errorMsg" ng-message="email">Invalid email address</div>
				<div class="errorMsg" ng-message="required">Required</div>
			</div>

			<br>
			<label>Username</label>
			<input class="form-control" ng-model="user.username" ng-change="validateUsername(user.username)" type="text" name="uName" required placeholder="Username">
			<span class="errorMsg">{{usernameExistsMsg}}</span>
			<div ng-messages="registerForm.uName.$error">
				<div class="errorMsg" ng-message="required">Required</div>
			</div>

			<br>
			<label>Password</label>
			<input class="form-control" ng-minlength="6" type="password" ng-model="user.password" name="password" required placeholder="Password">
			<div ng-messages="registerForm.password.$error">
				<div class="errorMsg" ng-message="minlength">Password should be 6 character minimum</div>
				<div class="errorMsg" ng-message="required">Required</div>
			</div>

			<br>
			<button class="btn btn-info" ng-click="addUser(user)" ng-disabled="registerForm.$invalid">Register</button>
			<br>
			<br>
			<a href="#/signIn">Already registered?......<strong>Log In</strong></a>
	</form>
</div>

registerController.js

myApp.controller('RegisterController', ['$scope', '$http', '$location', function($scope, $http, $location) {
	console.log("Register controller");

	$scope.addUser = function(user) {
		console.log("Add user called");
		$http.post('/users', {fname: user.fName, lname: user.lName, email: user.email, username: user.username, password: user.password}).success(function(response) {
			console.log("Add user response username: " + response.username);
		});

		this.validateRegistration(user.email);
	};

	$scope.validateEmail = function(email) {
		console.log("Validate email called");
		$http.get('/users/' + email).success(function(response) {
			if(response != null) {
				$scope.emailExistsMsg = response.email + " already exists";
			} else {
				$scope.emailExistsMsg = "";
			}
		});
	};

	$scope.validateRegistration = function(email) {
		$http.get('/users/' + email).success(function(response) {
			if(response != null) {
				console.log("Registration successful");
				$scope.registrationMsg = "Congratulations " + email + ". Registration successful";
				console.log($scope.registrationMsg);
				$location.path("/registrationStatus");

			} else {
				console.log("Registration not successful: " + response);
				$scope.registrationMsg = "Error with registration. Please try again or contact administrator.";
				console.log($scope.registrationMsg);
				$location.path("/registrationStatus");
			}
		});
	};
}]);

signinPage.html

<div class="container" ng-show="show">

	<br>
	<form name="signInForm" novalidate>
		<h2>Sign In</h2>
		<br>
		<label>Username</label>
		<input class="form-control" ng-model="user.username" type="text" name="username" required placeholder="Username">
		<br>
		<label>Password</label>
		<input class="form-control" ng-model="user.password" type="password" name="password" required placeholder="Password">
		<br>
		<button class="btn btn-info" ng-click="logIn(user.username, user.password)" ng-disabled="signInForm.$invalid">Sign In</button>
		<br>
		<br>
		<a href="#/register">Not registered?......<strong>Register</strong></a>
	</form>

</div>

signinController.js

myApp.controller('SignInController', ['$scope', '$http', '$location', function($scope, $http, $location) {
	console.log("Sign in controller");

	$scope.logIn = function(username, password) {
		console.log("Sign in called");

		$http.get('/users/' + username).success(function(response) {
			if(response != null) {
				if(username == response.username && password == response.password) {
					console.log("Successful log in");
					this.isDisabled = false;
					$location.path("/playSet");
				}
			} else {
				console.log("User not found: " + response);
			}
		});
	};
}]);

server.js

var express = require('express');
var app = express();
var mongojs = require('mongojs');
var db = mongojs('tracks', ['tracks']);
var db1 = mongojs('setlist', ['setlist']);
var db2 = mongojs('users', ['users']);
var bodyParser = require('body-parser');

app.use(express.static(__dirname = '\public'));
app.use(bodyParser.json());

app.get('/users/:email', function(req, res) {
	var email = req.params.email;
	console.log("Existing email validation: " + email);
	db2.users.findOne({email: email}, function(err, doc) {
		res.json(doc);
	});
});

app.get('/users/:username', function(req, res) {
	var username = req.params.username;
	console.log("User: " + username);
	db2.users.findOne({username: username}, function(err, doc) {
		res.json(doc);
	});
});

app.listen(3000);
console.log("Server running on port 3000");

【问题讨论】:

    标签: angularjs node.js express


    【解决方案1】:

    你不能有两条单独的路线:

    app.get('/users/:email', ...);
    app.get('/users/:username', ...);
    

    因为第二个永远不会被击中,因为第一个匹配相同的东西。您有以下选择:

    1. 更改其中一个的路径,使其与另一个不同。
    2. 将它们组合到一个路由处理程序中,并设计如何根据其他条件(查询参数、cookie、会话状态等)判断您要执行哪一段逻辑。
    3. 使用更复杂的路由定义(可能包括正则表达式),以便每个路由定义都能真正区分两条路由。

    如果(我只是从您的上下文中猜测一下),您尝试支持两种不同的方式来识别用户(一种是用户名,另一种是电子邮件地址),那么我建议您将它们合并到一个路由处理程序中,然后只需检查 :username 值以查看它是用户名还是电子邮件地址,并在您的路由中采取相应的行动。如果用户名中不允许使用 @ 符号,但电子邮件地址中需要使用此符号,则此方法可能有效。然后,您可以检查req.params.username 是否包含@ 符号,如果是,则转到电子邮件地址逻辑。

    // single route handler to handle either a username or email lookup
    app.get('/users/:username', function(req, res) {
        var username = req.params.username;
        if (username.indexOf("@") !== -1) {
            console.log("Existing email validation: " + username);
            db2.users.findOne({email: username}, function(err, doc) {
                res.json(doc);
            });
        } else {
            console.log("User: " + username);
            db2.users.findOne({username: username}, function(err, doc) {
                res.json(doc);
            });
        }
    });
    

    或者,也许更干一点:

    // single route handler to handle either a username or email lookup
    app.get('/users/:username', function(req, res) {
        // lookup either email address or username
        let name = req.params.username;
        let lookupObj = name.indexOf("@") !== -1 ? {email: name} : {username: name};
        db2.users.findOne(lookupObj, function(err, doc) {
            res.json(doc);
        });
    });
    

    或者,您可以使用唯一路径将路线分开:

    app.get('/users/email/:email', ...);
    app.get('/users/userID/:username', ...);
    

    【讨论】:

    • 太棒了。谢谢你。我分别为每条路由附加了“/email”和“/username”。
    • @bcooley1983 - 如果这些答案之一为您的问题提供了答案,那么您应该通过单击最佳答案旁边的绿色复选标记向社区表明这一点。遵循正确的程序,这也将为您赢得一些声誉积分。
    【解决方案2】:

    这个问题发布已经 4 年多了,我遇到了类似的问题。

    我想说明我是如何解决这个问题的。这可能会有所帮助。简而言之,我将控制器转换为中间件。

    我最初拥有的东西

    app.get('/users/:email', ...);
    app.get('/users/:id', ...);
    

    我删除了

    app.get('/users/:email', ...)
    

    然后变成了

    app.get('/users', getUserByEmail, ...otherControllers)
    

    然后,在getUserByEmail 中,我检查email 属性是否存在于req.query 对象上,并且如果它是查询对象上的唯一属性,则通过电子邮件搜索用户,否则,执行next 函数移动到下一个控制器/中间件。

     if(req.query.email !== undefined && Object.keys(req.query).length === 1){
       ... code to get user by email
       end if block with return
      }
      next()
    

    【讨论】:

      【解决方案3】:

      这些不是唯一的路线。

      与给定路径匹配的第一个路由将被使用,而不管提供的参数如何。

      这里有带有email 参数的路由/users/,然后是带有username 参数的相同路由/users/,永远不会被评估。

      如果你想使用这种风格的路由,你应该有一个带参数的/users/路由,然后在那个路由中评估参数以确定它是email还是username,并且然后在数据库上执行适当的查找。这不是一种简单或万无一失的方法,并且限制了某人将其电子邮件地址用作用户名等的可能性。因此,您应该强烈考虑使用独特的路线,例如 /users/email/:email 或类似的东西。

      就个人而言,我认为您的问题还因为您似乎想使用/users/ 进行注册和登录这一事实而感到困惑。您可能应该改用/login//register/ 之类的东西,尤其是这样您以后可以使用/users/ 来获取用户列表。但是,如果您必须使用相同的路由,您可以将它们分开 getpost,因为无论如何post 更常见于注册类型的场景。

      总体而言,感觉您需要花更多时间评估您的整体 API 使用和目的,以确定构建端点的正确方法。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-10-16
        • 2019-10-26
        • 2018-01-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多