jjzjj

javascript - 身份验证 - 调用 $http 的 .then() 成功回调而不是错误回调

coder 2024-07-23 原文

这可能只是因为误解了如何在 MEAN 堆栈应用程序中最好地进行身份验证,或者我对 promises 和 $http 的 .then() 方法如何工作缺乏了解,但每当我尝试使用不正确的凭据向我的后端节点服务器进行身份验证,它正在调用 $http 的 .then() 方法的成功回调而不是错误回调。这是我的设置:

我正在使用 jsonwebtokenexpress-jwt 包,AngularJS 拦截器将 token 添加到请求并检查状态 401 responseErrors,一个 TokenService 设置/删除等 JWT 和一个 UserService 来处理登录、注销等。

从调试来看,这是正在发生的事情:

  1. 发送登录请求
  2. 服务器捕获请求,查找指定用户,但无法在数据库中找到他们。返回 401 错误,JSON 对象包括错误消息等。
  3. HttpInterceptor 使用 responseError 方法,正确地看到它是状态 401,删除任何可能的现有 token ,重定向到 /login 屏幕,然后返回s $q.reject(response).
  4. UserService.login() 正确使用错误回调并执行返回响应
  5. 问题 - 我的 login.js .login() 方法中的成功回调运行,而不是第二个错误回调。我感觉这与 this article about promise chaining 中讨论的内容有关,但我的专业知识在这里有其局限性,我不太明白接下来我应该做什么来告诉链中的下一个回调,前一个回调有错误......

这是我的设置:

express :

authRoutes.js

authRoutes.post("/login", function (req, res) {

    User.findOne({username: req.body.username}, function (err, user) {
        if (err) res.status(500).send(err);
        if (!user) {
            res.status(401).send({success: false, message: "User with the provided username was not found"})
        } else if (user) {
            bcrypt.compare(req.body.password, user.password, function (err, match) {
                if (err) throw (err);
                if (!match) res.status(401).json({success: false, message: "Incorrect password"});
                else {
                    var token = jwt.sign(user, config.secret, {expiresIn: "24h"});
                    res.json({token: token, success: true, message: "Here's your token!"})
                }
            });
        }
    });
});

从调试来看,当我使用不正确的凭据登录时,它正确地命中了 res.status(401).send(...) 行,所以这部分似乎没问题。

Angular :

app.js(包括 HttpInterceptor)

var app = angular.module("TodoApp", ["ngRoute"]);

app.factory("AuthInterceptor", ["$q", "$location", "TokenService", function ($q, $location, TokenService) {
    return {
        request: function (config) {
            var token = TokenService.getToken();
            if (token) {
                config.headers = config.headers || {};
                config.headers.Authorization = "Bearer " + token
            }
            return config;
        },
        responseError: function (response) {
            if (response.status === 401) {
                TokenService.removeToken();
                $location.path("/login");
            }
            return $q.reject(response);
        }
    }
}]);

app.config(function ($routeProvider, $httpProvider) {
    $httpProvider.interceptors.push('AuthInterceptor');

    $routeProvider
        .when("/", {
            templateUrl: "landing/landing-page.html"
        });
});

用户服务.js

var app = angular.module("TodoApp");

app.service("UserService", ["$http", "TokenService", function ($http, TokenService) {

    this.signup = function (user) {
        return $http.post("http://localhost:8080/auth/signup", user).then(function (response) {
            return response;
        }, function (response) {
            return response;
        });
    };

    this.login = function (user) {
        return $http.post("http://localhost:8080/auth/login", user).then(function (response) {
            if (response.data.success) TokenService.setToken(response.data.token);
            return response;
        }, function (response) {
            return response;
        })
    };

    this.isAdmin = function (user) {
        return user.admin;
    };
}]);

login.js(问题似乎表现出来的地方)

var app = angular.module("TodoApp");

app.config(function ($routeProvider) {
    $routeProvider
        .when("/login", {
            templateUrl: "auth/login.html",
            controller: "LoginController"
        })
});

app.controller("LoginController", ["$scope", "$http", "$location", "UserService", "TokenService", function ($scope, $http, $location, UserService, TokenService) {

    $scope.login = function (user) {
        UserService.login(user).then(function (response) {
            $location.path("/todo");
        }, function (response) {
            console.log("There was a problem: " + response);
        });
    }
}]);

最后一部分,UserService.login(user).then(function (response) { $location.path("/todo"); 是正在运行并试图重定向用户到 Todo 项目列表,当我希望它运行 console.log("There was a problem: "+ response); 行而不是...

就像我上面说的,我觉得它与链接 promise 以及如何在链中途处理错误而不是通过链向下冒泡有关。不确定我是否需要像我上面提到的网站所说的那样添加 .catch() block 。即使这是答案,我也不确定如何写。

如果我有更好的组织方式,我也绝对乐于接受建议。我必须将这个教给一类学生,并希望确保我教的是好的做法。

在此先感谢您的帮助!

最佳答案

仔细看看这部分代码:

this.login = function (user) {
    return $http.post("http://localhost:8080/auth/login", user).then(function (response) {
        if (response.data.success) TokenService.setToken(response.data.token);
        return response;
    }, function (response) {
        return response;
    })
}

在这里,您提供了带有返回值的错误回调,该返回值传递给 promise 链中的下一个回调。您感到困惑的根源在于,如果您希望错误 进一步传播,您仍然需要从回调中返回被拒绝的 throw promise 。否则,这实际上意味着您已从错误情况中恢复,并且流程中的下一步将会成功。这就是你现在所拥有的。

在你的情况下,你要么完全删除错误回调

return $http.post("http://localhost:8080/auth/login", user).then(function (response) {
    if (response.data.success) TokenService.setToken(response.data.token);
    return response;
});

...或者确保你返回失败的 promise

return $http.post("http://localhost:8080/auth/login", user).then(function (response) {
    if (response.data.success) TokenService.setToken(response.data.token);
    return response;
}, function (response) {
    return $q.reject(response);
});

...或抛出:

return $http.post("http://localhost:8080/auth/login", user).then(function (response) {
    if (response.data.success) TokenService.setToken(response.data.token);
    return response;
}, function (response) {
    throw new Error(response);
});

关于javascript - 身份验证 - 调用 $http 的 .then() 成功回调而不是错误回调,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34276945/

有关javascript - 身份验证 - 调用 $http 的 .then() 成功回调而不是错误回调的更多相关文章

  1. ruby - 具有身份验证的私有(private) Ruby Gem 服务器 - 2

    我想安装一个带有一些身份验证的私有(private)Rubygem服务器。我希望能够使用公共(public)Ubuntu服务器托管内部gem。我读到了http://docs.rubygems.org/read/chapter/18.但是那个没有身份验证-如我所见。然后我读到了https://github.com/cwninja/geminabox.但是当我使用基本身份验证(他们在他们的Wiki中有)时,它会提示从我的服务器获取源。所以。如何制作带有身份验证的私有(private)Rubygem服务器?这是不可能的吗?谢谢。编辑:Geminabox问题。我尝试“捆绑”以安装新的gem..

  2. ruby - 如何模拟 Net::HTTP::Post? - 2

    是的,我知道最好使用webmock,但我想知道如何在RSpec中模拟此方法:defmethod_to_testurl=URI.parseurireq=Net::HTTP::Post.newurl.pathres=Net::HTTP.start(url.host,url.port)do|http|http.requestreq,foo:1endresend这是RSpec:let(:uri){'http://example.com'}specify'HTTPcall'dohttp=mock:httpNet::HTTP.stub!(:start).and_yieldhttphttp.shou

  3. ruby - 如何在 Rails 4 中使用表单对象之前的验证回调? - 2

    我有一个服务模型/表及其注册表。在表单中,我几乎拥有服务的所有字段,但我想在验证服务对象之前自动设置其中一些值。示例:--服务Controller#创建Action:defcreate@service=Service.new@service_form=ServiceFormObject.new(@service)@service_form.validate(params[:service_form_object])and@service_form.saverespond_with(@service_form,location:admin_services_path)end在验证@ser

  4. 使用 ACL 调用 upload_file 时出现 Ruby S3 "Access Denied"错误 - 2

    我正在尝试编写一个将文件上传到AWS并公开该文件的Ruby脚本。我做了以下事情:s3=Aws::S3::Resource.new(credentials:Aws::Credentials.new(KEY,SECRET),region:'us-west-2')obj=s3.bucket('stg-db').object('key')obj.upload_file(filename)这似乎工作正常,除了该文件不是公开可用的,而且我无法获得它的公共(public)URL。但是当我登录到S3时,我可以正常查看我的文件。为了使其公开可用,我将最后一行更改为obj.upload_file(file

  5. ruby - 如何验证 IO.copy_stream 是否成功 - 2

    这里有一个很好的答案解释了如何在Ruby中下载文件而不将其加载到内存中:https://stackoverflow.com/a/29743394/4852737require'open-uri'download=open('http://example.com/image.png')IO.copy_stream(download,'~/image.png')我如何验证下载文件的IO.copy_stream调用是否真的成功——这意味着下载的文件与我打算下载的文件完全相同,而不是下载一半的损坏文件?documentation说IO.copy_stream返回它复制的字节数,但是当我还没有下

  6. ruby - 有人可以帮助解释类创建的 post_initialize 回调吗 (Sandi Metz) - 2

    我正在阅读SandiMetz的POODR,并且遇到了一个我不太了解的编码原则。这是代码:classBicycleattr_reader:size,:chain,:tire_sizedefinitialize(args={})@size=args[:size]||1@chain=args[:chain]||2@tire_size=args[:tire_size]||3post_initialize(args)endendclassMountainBike此代码将为其各自的属性输出1,2,3,4,5。我不明白的是查找方法。当一辆山地自行车被实例化时,因为它没有自己的initialize方法

  7. c# - 如何在 ruby​​ 中调用 C# dll? - 2

    如何在ruby​​中调用C#dll? 最佳答案 我能想到几种可能性:为您的DLL编写(或找人编写)一个COM包装器,如果它还没有,则使用Ruby的WIN32OLE库来调用它;看看RubyCLR,其中一位作者是JohnLam,他继续在Microsoft从事IronRuby方面的工作。(估计不会再维护了,可能不支持.Net2.0以上的版本);正如其他地方已经提到的,看看使用IronRuby,如果这是您的技术选择。有一个主题是here.请注意,最后一篇文章实际上来自JohnLam(看起来像是2009年3月),他似乎很自在地断言RubyCL

  8. java - 从 JRuby 调用 Java 类的问题 - 2

    我正在尝试使用boilerpipe来自JRuby。我看过guide从JRuby调用Java,并成功地将它与另一个Java包一起使用,但无法弄清楚为什么同样的东西不能用于boilerpipe。我正在尝试基本上从JRuby中执行与此Java等效的操作:URLurl=newURL("http://www.example.com/some-location/index.html");Stringtext=ArticleExtractor.INSTANCE.getText(url);在JRuby中试过这个:require'java'url=java.net.URL.new("http://www

  9. ruby - 调用其他方法的 TDD 方法的正确方法 - 2

    我需要一些关于TDD概念的帮助。假设我有以下代码defexecute(command)casecommandwhen"c"create_new_characterwhen"i"display_inventoryendenddefcreate_new_character#dostufftocreatenewcharacterenddefdisplay_inventory#dostufftodisplayinventoryend现在我不确定要为什么编写单元测试。如果我为execute方法编写单元测试,那不是几乎涵盖了我对create_new_character和display_invent

  10. ruby - Net::HTTP 获取源代码和状态 - 2

    我目前正在使用以下方法获取页面的源代码:Net::HTTP.get(URI.parse(page.url))我还想获取HTTP状态,而无需发出第二个请求。有没有办法用另一种方法做到这一点?我一直在查看文档,但似乎找不到我要找的东西。 最佳答案 在我看来,除非您需要一些真正的低级访问或控制,否则最好使用Ruby的内置Open::URI模块:require'open-uri'io=open('http://www.example.org/')#=>#body=io.read[0,50]#=>"["200","OK"]io.base_ur

随机推荐