gpt4 book ai didi

ajax - 捕获 Aurelias HTTP 客户端中的错误

转载 作者:搜寻专家 更新时间:2023-10-30 21:29:48 26 4
gpt4 key购买 nike

大家好(尤其是在这里闲逛的 Aurelia 核心团队)

我有一个 aurelia 应用程序,它使用“aurelia-http-client”向我的后端 API 发出请求。

我的后端 API 是在 Nancy 上运行的基于 C# 的服务。

在我的前端,我将 http 客户端抽象到我自己的网络库中,如下所示:

import { inject } from 'aurelia-framework';
import { Router } from 'aurelia-router';
import { HttpClient } from 'aurelia-http-client';
import environment from './environment';

@inject(HttpClient, Router)
export default class httpservice {

private http: HttpClient = null;
private router: Router = null;
private authService: any = null;
private authToken: string = "";

constructor(HttpClient, Router) {

this.http = HttpClient;
this.router = Router;

HttpClient.configure(http => {
http.withBaseUrl(environment.servicebase);
});

}

public setAuthService(authService: any) {
this.authService = authService;
}

public get(url: string, authObject?: any): any {

let myAuth = this.authService ? this.authService : authObject;
let myToken = "";
if (myAuth) {
myToken = myAuth.getAuthToken();
}

let self = this;
let client = this.http
.createRequest(url)
.asGet()
.withHeader("AuthenticationToken", myToken)
.withInterceptor({
responseError(responseError) {
console.log(responseError);
if (responseError.statusCode === 401) {
if (myAuth) {
myAuth.destroySession();
}
}
if (responseError.statusCode === 404) {
self.router.navigateToRoute("missing");
}
return responseError;
}
});

return client;
}

public post(url: string, postData: any, authObject?: any): any {

let myAuth = this.authService ? this.authService : authObject;
let myToken = "";
if (myAuth) {
myToken = myAuth.getAuthToken();
}

let self = this;
let client = this.http
.createRequest(url)
.asPost().withContent(postData)
.withHeader("AuthenticationToken", myToken)
.withInterceptor({
responseError(responseError) {
console.log(responseError);
if (responseError.statusCode === 401) {
if (myAuth) {
myAuth.destroySession();
}
}
if (responseError.statusCode === 404) {
self.router.navigateToRoute("missing");
}
return responseError;
}
});

return client;
}

}

然后我在我的其他模块/类中使用它,如下所示:

import { Aurelia, inject } from 'aurelia-framework';
import HttpService from './httpservice';
import environment from './environment';
import { EventAggregator } from 'aurelia-event-aggregator';

@inject(EventAggregator, Aurelia, HttpService)
export default class Authservice {

public http: HttpService = null;
public app: Aurelia = null;
public ea: EventAggregator = null;
public authToken: any = null;

private loginUrl: string = "";
private logoutUrl: string = "";
private checkUrl: string = "";

constructor(eventAggregator, aurelia, httpService) {

this.http = httpService;
this.app = aurelia;
this.ea = eventAggregator;

this.loginUrl = "/login";
}

public getAuthToken() {
if (!sessionStorage[environment.tokenname] ||
(sessionStorage[environment.tokenname] == null)) {
return null;
}
return sessionStorage[environment.tokenname];
}

public login(loginName, password) {

let postData = {
loginName: loginName,
password: password
};

let client = this.http.post(this.loginUrl, postData);

client.send()
.then((response) => response.content)
.then((data) => {

if (data.error) {
this.ea.publish("loginMessage", { message: data.errorMessage });
return;
}

if (data.authenticationFailed) {
this.ea.publish("loginMessage", { message: "Invalid user name and/or password supplied." });
return;
}

if (data.accountSuspended) {
this.ea.publish("loginMessage", { message: "Your account has been suspended, please contact support." });
return;
}

sessionStorage[environment.tokenname] = data.token;
sessionStorage["displayedLoginName"] = data.displayName;
location.assign('#/');
this.app.setRoot('app');

})
.catch(() =>
{
debugger;
alert("Something bad happened trying to connect to server.");
});
}

public isAuthenticated() {
// TODO: hook this up to check auth token validity via rest call???
let token = this.getAuthToken();
return token !== null;
}

}

enum LoginStates {
LoginValid = 0,
BadUserNameOrPassword,
AccountSuspended
}

请注意我已经从 auth 库中删除了一些代码以减少混淆

总的来说,所有这些都运作良好。拦截器在 401 和 404 发生时被触发,如果我添加一个 500 也会被处理,所以一切都很好。

我遇到的问题是处理通信故障。

正如您在登录例程中看到的那样,我在 then 之后有一个问题。

我原以为如果无法访问服务器或发生其他一些基础通信故障,则会触发此捕获而不是“然后”,从而允许我处理错误,但事实并非如此。

我得到的是控制台中的这个:

Aurelia HTTP client error

更糟糕的是,我的登录例程并没有中止,它实际上成功了并允许显示登录页面。

似乎在库进行 OPTIONS 调用时(这是发生此错误的时间)我的用户代码没有被考虑在内。

成功的飞行前/ajax 请求需要 OPTIONS 调用,因此无法阻止这种情况的发生,我觉得如果 OPTIONS 调用没有中止,而是进入了 POST 调用,那我的错误就在这里然后将考虑处理。

无法捕获这样的错误似乎很愚蠢,尤其是在当今的移动世界中,设备可能不在覆盖范围内或暂时离线。

如果有人对如何解决这个问题有任何想法,我很乐意听取他们的意见。

更新1

我的问题似乎与这个有关: aurelia-fetch-client - a promise was rejected with a non-error: [object Response]

但是,我没有使用“useStandardConfiguration()”,这显然是造成这种情况的原因。我也没有使用 fetch 客户端,但我确实注意到两个客户端中的 API 实际上是相同的,所以我想知道底层代码是否也相似。

最佳答案

好吧....所以,经过一个漫长的下午挠头和扯头发之后,事实证明,整个事情实际上与 aurelia 用来管理的“BlueBird promises library”的报告问题有关这是 promise 。

BlueBird 问题的链接可在此处找到: https://github.com/petkaantonov/bluebird/issues/990

根据 BB 开发人员的说法,这并不是一个具体的问题,但对于遇到它的许多人来说,它看起来确实像一个问题。

最重要的是,库的设计目的不是抛出它直接生成的错误(如问题页面上的示例所示)

根据 BB 团队的说法,正确的方法是要么完全抛出一个新错误,要么从传递给 promise 的实例派生一个新实例,并在重新抛出之前更改它的参数。

当然,由于 Aurelia 中的抽象,这对我们大多数人来说不是一个选择,除非我们想着手更改 http 客户端库代码。

此部分的标记需要转到“TheBlueFox”以获取上面他/她的评论。

最终的解决方案如下所示:

import { inject } from 'aurelia-framework';
import { Router } from 'aurelia-router';
import { HttpClient, Interceptor } from 'aurelia-http-client';
import environment from './environment';
import Debugger = require("_debugger");

@inject(HttpClient, Router)
export default class httpservice {

private http: HttpClient = null;
private router: Router = null;
private authService: any = null;
private authToken: string = "";
private myInterceptors: Interceptor;

constructor(HttpClient, Router) {

this.http = HttpClient;
this.router = Router;

HttpClient.configure(http => {
http.withBaseUrl(environment.servicebase);
http.withInterceptor(new HttpInterceptors());
});

}

public setAuthService(authService: any) {
this.authService = authService;
}

public get(url: string, authObject?: any): any {

let myAuth = this.authService ? this.authService : authObject;
let myToken = "";
if (myAuth) {
myToken = myAuth.getAuthToken();
}

let client = this.http
.createRequest(url)
.asGet()
.withHeader("AuthenticationToken", myToken);

return client;
}

public post(url: string, postData: any, authObject?: any): any {

let myAuth = this.authService ? this.authService : authObject;
let myToken = "";
if (myAuth) {
myToken = myAuth.getAuthToken();
}

let self = this;

let client = this.http
.createRequest(url)
.asPost().withContent(postData)
.withHeader("AuthenticationToken", myToken);

return client;
}

}

class HttpInterceptors implements Interceptor {

responceError(error)
{

if (error.statusCode === 0) {
throw new Error("Could not contact server");
}

if (error.statusCode === 401) {
// do auth handling here
}

if (error.statusCode === 404) {
// do 404 handling here
}

return error;

}
}

神奇之处在于附加到我的 HttpService 底部的 HttpInterceptors 类。您应该能够看到状态代码为 0 的检查,并且此处执行的实际操作是引发新错误。

正是抛出这个新错误的操作导致捕获到对 http 客户端的实际调用中的“catch”。

如果你在那个时候不抛出,那么一切都会分崩离析,你会看到我原来的问题帖子中看到的场景,抛出,你就会捕获它并在用户代码中处理它。

这种做事方式在 aurelia-fetch-client 中也很明显,因为它使用 BlueBird promise 库以大致相似的方式工作。

关于ajax - 捕获 Aurelias HTTP 客户端中的错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42903942/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com