Merge pull request #4805 from mempool/mononaut/http-error-handling

http error handling
This commit is contained in:
softsimon 2024-03-23 18:03:24 +09:00 committed by GitHub
commit 1b21cd89a3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
14 changed files with 118 additions and 54 deletions

View file

@ -98,11 +98,9 @@
</ng-template>
<ng-template [ngIf]="error">
<div class="text-center">
Error loading address data.
<br>
<i>{{ error.error }}</i>
</div>
<app-http-error [error]="error">
<span i18n="address.error.loading-address-data">Error loading address data.</span>
</app-http-error>
</ng-template>
</div>

View file

@ -135,11 +135,10 @@
<ng-template [ngIf]="error">
<br>
<div class="text-center">
<span i18n="address.error.loading-address-data">Error loading address data.</span>
<br>
<ng-template #displayServerError><i class="small">({{ error.error }})</i></ng-template>
<ng-template [ngIf]="error.status === 413 || error.status === 405 || error.status === 504" [ngIfElse]="displayServerError">
<ng-template [ngIf]="error.status === 413 || error.status === 405 || error.status === 504" [ngIfElse]="displayServerError">
<div class="text-center">
<span i18n="address.error.loading-address-data">Error loading address data.</span>
<br>
<ng-container i18n="Electrum server limit exceeded error">
<i>There many transactions on this address, more than your backend can handle. See more on <a href="/docs/faq#address-lookup-issues">setting up a stronger backend</a>.</i>
<br><br>
@ -150,9 +149,14 @@
<br>
<a href="http://mempoolhqx4isw62xs7abwphsq7ldayuidyx2v2oethdhhj6mlo2r6ad.onion/address/{{ addressString }}" target="_blank">http://mempoolhqx4isw62xs7abwphsq7ldayuidyx2v2oethdhhj6mlo2r6ad.onion/address/{{ addressString }}</a>
<br><br>
<i class="small">({{ error.error }})</i>
</ng-template>
</div>
<i class="small">({{ error | httpErrorMsg }})</i>
</div>
</ng-template>
<ng-template #displayServerError>
<app-http-error [error]="error">
<span i18n="address.error.loading-address-data">Error loading address data.</span>
</app-http-error>
</ng-template>
</ng-template>
</div>

View file

@ -140,10 +140,22 @@ export class AddressComponent implements OnInit, OnDestroy {
if (!fetchTxs.length) {
return of([]);
}
return this.apiService.getTransactionTimes$(fetchTxs);
return this.apiService.getTransactionTimes$(fetchTxs).pipe(
catchError((err) => {
this.isLoadingAddress = false;
this.isLoadingTransactions = false;
this.error = err;
this.seoService.logSoft404();
console.log(err);
return of([]);
})
);
})
)
.subscribe((times: number[]) => {
.subscribe((times: number[] | null) => {
if (!times) {
return;
}
times.forEach((time, index) => {
this.tempTransactions[this.timeTxIndexes[index]].firstSeen = time;
});

View file

@ -146,13 +146,10 @@
</ng-template>
<ng-template [ngIf]="error">
<div class="text-center">
<app-http-error [error]="error">
<span i18n="asset.error.loading-asset-data">Error loading asset data.</span>
<br>
<i>{{ error.error }}</i>
</div>
</app-http-error>
</ng-template>
</div>
<br>

View file

@ -46,9 +46,7 @@
</ng-template>
<ng-template [ngIf]="error">
<div class="text-center">
<ng-container i18n="Asset data load error">Error loading assets data.</ng-container>
<br>
<i>{{ error.error }}</i>
</div>
<app-http-error [error]="error">
<span i18n="Asset data load error">Error loading assets data.</span>
</app-http-error>
</ng-template>

View file

@ -338,14 +338,12 @@
<app-transactions-list [transactions]="transactions" [paginated]="true" [blockTime]="block.timestamp"></app-transactions-list>
<ng-template [ngIf]="transactionsError">
<div class="text-center">
<br>
<br>
<app-http-error [error]="transactionsError">
<span i18n="error.general-loading-data">Error loading data.</span>
<br><br>
<i>{{ transactionsError.status }}: {{ transactionsError.error }}</i>
<br>
<br>
</div>
</app-http-error>
<br>
<br>
</ng-template>
<ng-template [ngIf]="isLoadingTransactions && !transactionsError">
@ -378,11 +376,9 @@
<br>
</ng-template>
<ng-template [ngIf]="error">
<div class="text-center">
<app-http-error [error]="error">
<span i18n="error.general-loading-data">Error loading data.</span>
<br><br>
<i>{{ error.status }}: {{ error.error }}</i>
</div>
</app-http-error>
</ng-template>
<ng-template #headerLoader>

View file

@ -517,9 +517,9 @@
</div>
<ng-template #errorTemplate>
<div class="text-center">
<h3>{{ error.error }}</h3>
</div>
<app-http-error [error]="error">
<span i18n="transaction.error.loading-transaction-data">Error loading transaction data.</span>
</app-http-error>
</ng-template>
</ng-template>

View file

@ -66,9 +66,7 @@
</div>
<ng-template [ngIf]="error">
<div class="text-center">
<app-http-error [error]="error">
<span i18n="error.general-loading-data">Error loading data.</span>
<br><br>
<i>{{ error.status }}: {{ error.error }}</i>
</div>
</app-http-error>
</ng-template>

View file

@ -1,7 +1,7 @@
import { Inject, Injectable, PLATFORM_ID } from '@angular/core';
import { HttpInterceptor, HttpEvent, HttpRequest, HttpHandler, HttpResponse, HttpHeaders } from '@angular/common/http';
import { HttpInterceptor, HttpEvent, HttpRequest, HttpHandler, HttpResponse, HttpErrorResponse, HttpHeaders } from '@angular/common/http';
import { Observable, of } from 'rxjs';
import { tap } from 'rxjs/operators';
import { catchError, tap } from 'rxjs/operators';
import { TransferState, makeStateKey } from '@angular/platform-browser';
import { isPlatformBrowser } from '@angular/common';
@ -36,15 +36,41 @@ export class HttpCacheInterceptor implements HttpInterceptor {
}
return next.handle(request)
.pipe(tap((event: HttpEvent<any>) => {
if (!this.isBrowser && event instanceof HttpResponse) {
let keyId = request.url.split('/').slice(3).join('/');
const headers = {};
for (const k of event.headers.keys()) {
headers[k] = event.headers.getAll(k);
.pipe(
tap((event: HttpEvent<any>) => {
if (!this.isBrowser && event instanceof HttpResponse) {
let keyId = request.url.split('/').slice(3).join('/');
const headers = {};
for (const k of event.headers.keys()) {
headers[k] = event.headers.getAll(k);
}
this.transferState.set<any>(makeStateKey('/' + keyId), { response: event, headers });
}
this.transferState.set<any>(makeStateKey('/' + keyId), { response: event, headers });
}
}));
}),
catchError((e) => {
if (e instanceof HttpErrorResponse) {
if (e.status === 0) {
throw new HttpErrorResponse({
error: 'Unknown error',
headers: e.headers,
status: 0,
statusText: 'Unknown error',
url: e.url,
});
} else {
throw e;
}
} else {
const msg = e?.['message'] || 'Unknown error';
throw new HttpErrorResponse({
error: msg,
headers: new HttpHeaders(),
status: 0,
statusText: msg,
url: '',
});
}
})
);
}
}

View file

@ -0,0 +1,4 @@
<div class="http-error">
<p><b><ng-content></ng-content></b></p>
<i class="small">({{ error | httpErrorMsg }})</i>
</div>

View file

@ -0,0 +1,5 @@
.http-error {
width: 100%;
margin: 1em auto;
text-align: center;
}

View file

@ -0,0 +1,11 @@
import { HttpErrorResponse } from '@angular/common/http';
import { Component, Input } from '@angular/core';
@Component({
selector: 'app-http-error',
templateUrl: './http-error.component.html',
styleUrls: ['./http-error.component.scss']
})
export class HttpErrorComponent {
@Input() error: HttpErrorResponse | null;
}

View file

@ -0,0 +1,9 @@
import { HttpErrorResponse } from '@angular/common/http';
import { Pipe, PipeTransform } from '@angular/core';
@Pipe({ name: 'httpErrorMsg' })
export class HttpErrorPipe implements PipeTransform {
transform(e: HttpErrorResponse | null): string {
return e ? `${e.status}: ${e.statusText}` : '';
}
}

View file

@ -21,6 +21,7 @@ import { ScriptpubkeyTypePipe } from './pipes/scriptpubkey-type-pipe/scriptpubke
import { BytesPipe } from './pipes/bytes-pipe/bytes.pipe';
import { WuBytesPipe } from './pipes/bytes-pipe/wubytes.pipe';
import { FiatCurrencyPipe } from './pipes/fiat-currency.pipe';
import { HttpErrorPipe } from './pipes/http-error-pipe/http-error.pipe';
import { BlockchainComponent } from '../components/blockchain/blockchain.component';
import { TimeComponent } from '../components/time/time.component';
import { ClipboardComponent } from '../components/clipboard/clipboard.component';
@ -104,6 +105,7 @@ import { ClockFaceComponent } from '../components/clock-face/clock-face.componen
import { ClockComponent } from '../components/clock/clock.component';
import { CalculatorComponent } from '../components/calculator/calculator.component';
import { BitcoinsatoshisPipe } from '../shared/pipes/bitcoinsatoshis.pipe';
import { HttpErrorComponent } from '../shared/components/http-error/http-error.component';
import { OnlyVsizeDirective, OnlyWeightDirective } from './components/weight-directives/weight-directives';
@ -133,6 +135,7 @@ import { OnlyVsizeDirective, OnlyWeightDirective } from './components/weight-dir
Decimal2HexPipe,
FeeRoundingPipe,
FiatCurrencyPipe,
HttpErrorPipe,
ColoredPriceDirective,
BrowserOnlyDirective,
ServerOnlyDirective,
@ -208,6 +211,7 @@ import { OnlyVsizeDirective, OnlyWeightDirective } from './components/weight-dir
AccelerationsListComponent,
AccelerationStatsComponent,
PendingStatsComponent,
HttpErrorComponent,
],
imports: [
CommonModule,
@ -262,6 +266,7 @@ import { OnlyVsizeDirective, OnlyWeightDirective } from './components/weight-dir
VbytesPipe,
WuBytesPipe,
FiatCurrencyPipe,
HttpErrorPipe,
CeilPipe,
ShortenStringPipe,
CapAddressPipe,
@ -327,6 +332,7 @@ import { OnlyVsizeDirective, OnlyWeightDirective } from './components/weight-dir
AccelerationsListComponent,
AccelerationStatsComponent,
PendingStatsComponent,
HttpErrorComponent,
MempoolBlockOverviewComponent,
ClockchainComponent,