Refine error handling in RequestHandler and the console slightly (#2177)

If we don't explicitly handle random unexpected exceptions, the error
that the front end receives includes a big ole stacktrace, which is
unhelpful for regular users and possibly bad to expose. Instead, we
should provide a vague "something went wrong" message.

Separately, we can create a default SnackBar options and use that (we
want it longer than 1.5 seconds because that's pretty short).
This commit is contained in:
gbrodman 2023-10-12 14:03:12 -04:00 committed by GitHub
parent 36bd508bf9
commit a63916b08e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 37 additions and 18 deletions

View file

@ -48,6 +48,7 @@ import { DomainsWidgetComponent } from './home/widgets/domains-widget.component'
import { SettingsWidgetComponent } from './home/widgets/settings-widget.component'; import { SettingsWidgetComponent } from './home/widgets/settings-widget.component';
import { UserDataService } from './shared/services/userData.service'; import { UserDataService } from './shared/services/userData.service';
import WhoisComponent from './settings/whois/whois.component'; import WhoisComponent from './settings/whois/whois.component';
import { SnackBarModule } from './snackbar.module';
@NgModule({ @NgModule({
declarations: [ declarations: [
@ -79,6 +80,7 @@ import WhoisComponent from './settings/whois/whois.component';
FormsModule, FormsModule,
HttpClientModule, HttpClientModule,
MaterialModule, MaterialModule,
SnackBarModule,
], ],
providers: [ providers: [
BackendService, BackendService,

View file

@ -89,8 +89,6 @@ export class RegistrarService implements GlobalLoader {
} }
loadingTimeout() { loadingTimeout() {
this._snackBar.open('Timeout loading registrars', undefined, { this._snackBar.open('Timeout loading registrars');
duration: 1500,
});
} }
} }

View file

@ -129,9 +129,7 @@ export class ContactDetailsDialogComponent {
operationObservable.subscribe({ operationObservable.subscribe({
complete: this.onCloseCallback.bind(this), complete: this.onCloseCallback.bind(this),
error: (err: HttpErrorResponse) => { error: (err: HttpErrorResponse) => {
this._snackBar.open(err.error, undefined, { this._snackBar.open(err.error);
duration: 1500,
});
}, },
}); });
} }
@ -175,9 +173,7 @@ export default class ContactComponent {
if (confirm(`Please confirm contact ${contact.name} delete`)) { if (confirm(`Please confirm contact ${contact.name} delete`)) {
this.contactService.deleteContact(contact).subscribe({ this.contactService.deleteContact(contact).subscribe({
error: (err: HttpErrorResponse) => { error: (err: HttpErrorResponse) => {
this._snackBar.open(err.error, undefined, { this._snackBar.open(err.error);
duration: 1500,
});
}, },
}); });
} }

View file

@ -64,9 +64,7 @@ export default class SecurityComponent {
this.resetDataSource(); this.resetDataSource();
}, },
error: (err: HttpErrorResponse) => { error: (err: HttpErrorResponse) => {
this._snackBar.open(err.error, undefined, { this._snackBar.open(err.error);
duration: 1500,
});
}, },
}); });
this.cancel(); this.cancel();

View file

@ -61,9 +61,8 @@ export default class WhoisComponent {
this.resetDataSource(); this.resetDataSource();
}, },
error: (err: HttpErrorResponse) => { error: (err: HttpErrorResponse) => {
this._snackBar.open(err.error, undefined, { this._snackBar.open(err.error);
duration: 1500, this.loading = false;
});
}, },
}); });
this.cancel(); this.cancel();

View file

@ -49,8 +49,6 @@ export class UserDataService implements GlobalLoader {
} }
loadingTimeout() { loadingTimeout() {
this._snackBar.open('Timeout loading user data', undefined, { this._snackBar.open('Timeout loading user data');
duration: 1500,
});
} }
} }

View file

@ -0,0 +1,24 @@
// Copyright 2023 The Nomulus Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import { NgModule } from '@angular/core';
import { MAT_SNACK_BAR_DEFAULT_OPTIONS } from '@angular/material/snack-bar';
/** Provides a default set of options for the snack bar. */
@NgModule({
providers: [
{ provide: MAT_SNACK_BAR_DEFAULT_OPTIONS, useValue: { duration: 5000 } },
],
})
export class SnackBarModule {}

View file

@ -17,6 +17,7 @@ package google.registry.request;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.net.MediaType.PLAIN_TEXT_UTF_8; import static com.google.common.net.MediaType.PLAIN_TEXT_UTF_8;
import static javax.servlet.http.HttpServletResponse.SC_FORBIDDEN; import static javax.servlet.http.HttpServletResponse.SC_FORBIDDEN;
import static javax.servlet.http.HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
import static javax.servlet.http.HttpServletResponse.SC_METHOD_NOT_ALLOWED; import static javax.servlet.http.HttpServletResponse.SC_METHOD_NOT_ALLOWED;
import static javax.servlet.http.HttpServletResponse.SC_NOT_FOUND; import static javax.servlet.http.HttpServletResponse.SC_NOT_FOUND;
@ -162,6 +163,9 @@ public class RequestHandler<C> {
} catch (HttpException e) { } catch (HttpException e) {
e.send(rsp); e.send(rsp);
success = false; success = false;
} catch (Exception e) {
rsp.setStatus(SC_INTERNAL_SERVER_ERROR);
rsp.getWriter().write("Internal server error, please try again later");
} finally { } finally {
requestMetrics.record( requestMetrics.record(
new Duration(startTime, clock.nowUtc()), new Duration(startTime, clock.nowUtc()),