mirror of
				https://codeberg.org/yeentown/barkey.git
				synced 2025-11-03 23:14:13 +00:00 
			
		
		
		
	feat(server): Misskey Webでユーザーフレンドリーなエラーページを出す (#10590)
* (add) user-friendly error page * Update CHANGELOG.md * (add) cache-control header * Add ClientLoggerService * Log params and query * remove error stack on client * fix pug * 文面を調整 * :art] --------- Co-authored-by: tamaina <tamaina@hotmail.co.jp>
This commit is contained in:
		
							parent
							
								
									5d56799070
								
							
						
					
					
						commit
						49749b46c4
					
				
					 7 changed files with 218 additions and 1 deletions
				
			
		| 
						 | 
				
			
			@ -25,6 +25,8 @@
 | 
			
		|||
-
 | 
			
		||||
 | 
			
		||||
### Server
 | 
			
		||||
- Misskey Webでのサーバーサイドエラー画面を改善
 | 
			
		||||
- Misskey Webでのサーバーサイドエラーのログが残るように
 | 
			
		||||
- ノート作成時のアンテナ追加パフォーマンスを改善
 | 
			
		||||
- フォローインポートなどでの大量のフォロー等操作をキューイングするように #10544 @nmkj-io
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -45,7 +45,7 @@ gulp.task('build:backend:script', () => {
 | 
			
		|||
});
 | 
			
		||||
 | 
			
		||||
gulp.task('build:backend:style', () => {
 | 
			
		||||
	return gulp.src(['./packages/backend/src/server/web/style.css', './packages/backend/src/server/web/bios.css', './packages/backend/src/server/web/cli.css'])
 | 
			
		||||
	return gulp.src(['./packages/backend/src/server/web/style.css', './packages/backend/src/server/web/bios.css', './packages/backend/src/server/web/cli.css', './packages/backend/src/server/web/error.css'])
 | 
			
		||||
		.pipe(cssnano({
 | 
			
		||||
			zindex: false
 | 
			
		||||
		}))
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -34,6 +34,7 @@ import { QueueStatsChannelService } from './api/stream/channels/queue-stats.js';
 | 
			
		|||
import { ServerStatsChannelService } from './api/stream/channels/server-stats.js';
 | 
			
		||||
import { UserListChannelService } from './api/stream/channels/user-list.js';
 | 
			
		||||
import { OpenApiServerService } from './api/openapi/OpenApiServerService.js';
 | 
			
		||||
import { ClientLoggerService } from './web/ClientLoggerService.js';
 | 
			
		||||
import { RoleTimelineChannelService } from './api/stream/channels/role-timeline.js';
 | 
			
		||||
 | 
			
		||||
@Module({
 | 
			
		||||
| 
						 | 
				
			
			@ -43,6 +44,7 @@ import { RoleTimelineChannelService } from './api/stream/channels/role-timeline.
 | 
			
		|||
	],
 | 
			
		||||
	providers: [
 | 
			
		||||
		ClientServerService,
 | 
			
		||||
		ClientLoggerService,
 | 
			
		||||
		FeedService,
 | 
			
		||||
		UrlPreviewService,
 | 
			
		||||
		ActivityPubServerService,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										14
									
								
								packages/backend/src/server/web/ClientLoggerService.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								packages/backend/src/server/web/ClientLoggerService.ts
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,14 @@
 | 
			
		|||
import { Injectable } from '@nestjs/common';
 | 
			
		||||
import type Logger from '@/logger.js';
 | 
			
		||||
import { LoggerService } from '@/core/LoggerService.js';
 | 
			
		||||
 | 
			
		||||
@Injectable()
 | 
			
		||||
export class ClientLoggerService {
 | 
			
		||||
	public logger: Logger;
 | 
			
		||||
 | 
			
		||||
	constructor(
 | 
			
		||||
		private loggerService: LoggerService,
 | 
			
		||||
	) {
 | 
			
		||||
		this.logger = this.loggerService.getLogger('client');
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,6 +1,7 @@
 | 
			
		|||
import { dirname } from 'node:path';
 | 
			
		||||
import { fileURLToPath } from 'node:url';
 | 
			
		||||
import { Inject, Injectable } from '@nestjs/common';
 | 
			
		||||
import { v4 as uuid } from 'uuid';
 | 
			
		||||
import { createBullBoard } from '@bull-board/api';
 | 
			
		||||
import { BullAdapter } from '@bull-board/api/bullAdapter.js';
 | 
			
		||||
import { FastifyAdapter } from '@bull-board/fastify';
 | 
			
		||||
| 
						 | 
				
			
			@ -26,6 +27,7 @@ import { GalleryPostEntityService } from '@/core/entities/GalleryPostEntityServi
 | 
			
		|||
import { ClipEntityService } from '@/core/entities/ClipEntityService.js';
 | 
			
		||||
import { ChannelEntityService } from '@/core/entities/ChannelEntityService.js';
 | 
			
		||||
import type { ChannelsRepository, ClipsRepository, FlashsRepository, GalleryPostsRepository, NotesRepository, PagesRepository, UserProfilesRepository, UsersRepository } from '@/models/index.js';
 | 
			
		||||
import type Logger from '@/logger.js';
 | 
			
		||||
import { deepClone } from '@/misc/clone.js';
 | 
			
		||||
import { bindThis } from '@/decorators.js';
 | 
			
		||||
import { FlashEntityService } from '@/core/entities/FlashEntityService.js';
 | 
			
		||||
| 
						 | 
				
			
			@ -34,6 +36,7 @@ import manifest from './manifest.json' assert { type: 'json' };
 | 
			
		|||
import { FeedService } from './FeedService.js';
 | 
			
		||||
import { UrlPreviewService } from './UrlPreviewService.js';
 | 
			
		||||
import type { FastifyInstance, FastifyPluginOptions, FastifyReply } from 'fastify';
 | 
			
		||||
import { ClientLoggerService } from './ClientLoggerService.js';
 | 
			
		||||
 | 
			
		||||
const _filename = fileURLToPath(import.meta.url);
 | 
			
		||||
const _dirname = dirname(_filename);
 | 
			
		||||
| 
						 | 
				
			
			@ -46,6 +49,8 @@ const viteOut = `${_dirname}/../../../../../built/_vite_/`;
 | 
			
		|||
 | 
			
		||||
@Injectable()
 | 
			
		||||
export class ClientServerService {
 | 
			
		||||
	private logger: Logger;
 | 
			
		||||
 | 
			
		||||
	constructor(
 | 
			
		||||
		@Inject(DI.config)
 | 
			
		||||
		private config: Config,
 | 
			
		||||
| 
						 | 
				
			
			@ -85,6 +90,7 @@ export class ClientServerService {
 | 
			
		|||
		private urlPreviewService: UrlPreviewService,
 | 
			
		||||
		private feedService: FeedService,
 | 
			
		||||
		private roleService: RoleService,
 | 
			
		||||
		private clientLoggerService: ClientLoggerService,
 | 
			
		||||
 | 
			
		||||
		@Inject('queue:system') public systemQueue: SystemQueue,
 | 
			
		||||
		@Inject('queue:endedPollNotification') public endedPollNotificationQueue: EndedPollNotificationQueue,
 | 
			
		||||
| 
						 | 
				
			
			@ -649,6 +655,24 @@ export class ClientServerService {
 | 
			
		|||
			return await renderBase(reply);
 | 
			
		||||
		});
 | 
			
		||||
 | 
			
		||||
		fastify.setErrorHandler(async (error, request, reply) => {
 | 
			
		||||
			const errId = uuid();
 | 
			
		||||
			this.clientLoggerService.logger.error(`Internal error occured in ${request.routerPath}: ${error.message}`, {
 | 
			
		||||
				path: request.routerPath,
 | 
			
		||||
				params: request.params,
 | 
			
		||||
				query: request.query,
 | 
			
		||||
				code: error.name,
 | 
			
		||||
				stack: error.stack,
 | 
			
		||||
				id: errId,
 | 
			
		||||
			});
 | 
			
		||||
			reply.code(500);
 | 
			
		||||
			reply.header('Cache-Control', 'max-age=10, must-revalidate');
 | 
			
		||||
			return await reply.view('error', {
 | 
			
		||||
				code: error.code,
 | 
			
		||||
				id: errId,
 | 
			
		||||
			});
 | 
			
		||||
		});
 | 
			
		||||
 | 
			
		||||
		done();
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										110
									
								
								packages/backend/src/server/web/error.css
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										110
									
								
								packages/backend/src/server/web/error.css
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,110 @@
 | 
			
		|||
* {
 | 
			
		||||
    font-family: BIZ UDGothic, Roboto, HelveticaNeue, Arial, sans-serif;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#misskey_app,
 | 
			
		||||
#splash {
 | 
			
		||||
    display: none !important;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
body,
 | 
			
		||||
html {
 | 
			
		||||
    background-color: #222;
 | 
			
		||||
    color: #dfddcc;
 | 
			
		||||
    justify-content: center;
 | 
			
		||||
    margin: auto;
 | 
			
		||||
    padding: 10px;
 | 
			
		||||
    text-align: center;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
button {
 | 
			
		||||
    border-radius: 999px;
 | 
			
		||||
    padding: 0px 12px 0px 12px;
 | 
			
		||||
    border: none;
 | 
			
		||||
    cursor: pointer;
 | 
			
		||||
    margin-bottom: 12px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.button-big {
 | 
			
		||||
    background: linear-gradient(90deg, rgb(134, 179, 0), rgb(74, 179, 0));
 | 
			
		||||
    line-height: 50px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.button-big:hover {
 | 
			
		||||
    background: rgb(153, 204, 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.button-small {
 | 
			
		||||
    background: #444;
 | 
			
		||||
    line-height: 40px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.button-small:hover {
 | 
			
		||||
    background: #555;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.button-label-big {
 | 
			
		||||
    color: #222;
 | 
			
		||||
    font-weight: bold;
 | 
			
		||||
    font-size: 20px;
 | 
			
		||||
    padding: 12px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.button-label-small {
 | 
			
		||||
    color: rgb(153, 204, 0);
 | 
			
		||||
    font-size: 16px;
 | 
			
		||||
    padding: 12px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
a {
 | 
			
		||||
    color: rgb(134, 179, 0);
 | 
			
		||||
    text-decoration: none;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
p,
 | 
			
		||||
li {
 | 
			
		||||
    font-size: 16px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.dont-worry,
 | 
			
		||||
#msg {
 | 
			
		||||
    font-size: 18px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.icon-warning {
 | 
			
		||||
    color: #dec340;
 | 
			
		||||
    height: 4rem;
 | 
			
		||||
    padding-top: 2rem;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
h1 {
 | 
			
		||||
    font-size: 32px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
code {
 | 
			
		||||
    display: block;
 | 
			
		||||
    font-family: Fira, FiraCode, monospace;
 | 
			
		||||
    background: #333;
 | 
			
		||||
    padding: 0.5rem 1rem;
 | 
			
		||||
    max-width: 40rem;
 | 
			
		||||
    border-radius: 10px;
 | 
			
		||||
    justify-content: center;
 | 
			
		||||
    margin: auto;
 | 
			
		||||
    white-space: pre-wrap;
 | 
			
		||||
    word-break: break-word;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
summary {
 | 
			
		||||
    cursor: pointer;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
summary > * {
 | 
			
		||||
    display: inline;
 | 
			
		||||
    white-space: pre-wrap;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@media screen and (max-width: 500px) {
 | 
			
		||||
    details {
 | 
			
		||||
        width: 50%;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										65
									
								
								packages/backend/src/server/web/views/error.pug
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										65
									
								
								packages/backend/src/server/web/views/error.pug
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,65 @@
 | 
			
		|||
doctype html
 | 
			
		||||
 | 
			
		||||
//
 | 
			
		||||
	-
 | 
			
		||||
	  _____ _         _           
 | 
			
		||||
	 |     |_|___ ___| |_ ___ _ _ 
 | 
			
		||||
	 | | | | |_ -|_ -| '_| -_| | |
 | 
			
		||||
	 |_|_|_|_|___|___|_,_|___|_  |
 | 
			
		||||
							 |___|
 | 
			
		||||
	 Thank you for using Misskey!
 | 
			
		||||
	 If you are reading this message... how about joining the development?
 | 
			
		||||
	 https://github.com/misskey-dev/misskey
 | 
			
		||||
	 
 | 
			
		||||
 | 
			
		||||
html
 | 
			
		||||
 | 
			
		||||
	head
 | 
			
		||||
		meta(charset='utf-8')
 | 
			
		||||
		meta(name='viewport' content='width=device-width, initial-scale=1')
 | 
			
		||||
		meta(name='application-name' content='Misskey')
 | 
			
		||||
		meta(name='referrer' content='origin')
 | 
			
		||||
 | 
			
		||||
		title
 | 
			
		||||
			block title
 | 
			
		||||
				= 'An error has occurred... | Misskey'
 | 
			
		||||
 | 
			
		||||
		style
 | 
			
		||||
			include ../error.css
 | 
			
		||||
 | 
			
		||||
body
 | 
			
		||||
	svg.icon-warning(xmlns="http://www.w3.org/2000/svg", viewBox="0 0 24 24", stroke-width="2", stroke="currentColor", fill="none", stroke-linecap="round", stroke-linejoin="round")
 | 
			
		||||
		path(stroke="none", d="M0 0h24v24H0z", fill="none")
 | 
			
		||||
		path(d="M12 9v2m0 4v.01")
 | 
			
		||||
		path(d="M5 19h14a2 2 0 0 0 1.84 -2.75l-7.1 -12.25a2 2 0 0 0 -3.5 0l-7.1 12.25a2 2 0 0 0 1.75 2.75")
 | 
			
		||||
	
 | 
			
		||||
	h1 An error has occurred!
 | 
			
		||||
 | 
			
		||||
	button.button-big(onclick="location.reload();")
 | 
			
		||||
		span.button-label-big Refresh
 | 
			
		||||
	
 | 
			
		||||
	p.dont-worry Don't worry, it's (probably) not your fault.
 | 
			
		||||
 | 
			
		||||
	p If reloading after a period of time does not resolve the problem, contact the server administrator with the following ERROR ID.
 | 
			
		||||
 | 
			
		||||
	div#errors
 | 
			
		||||
		code.
 | 
			
		||||
			ERROR CODE: #{code}
 | 
			
		||||
			ERROR ID: #{id}
 | 
			
		||||
 | 
			
		||||
	p You may also try the following options:
 | 
			
		||||
 | 
			
		||||
	p Update your os and browser.
 | 
			
		||||
	p Disable an adblocker.
 | 
			
		||||
 | 
			
		||||
	a(href="/flush")
 | 
			
		||||
		button.button-small
 | 
			
		||||
			span.button-label-small Clear preferences and cache
 | 
			
		||||
	br
 | 
			
		||||
	a(href="/cli")
 | 
			
		||||
		button.button-small
 | 
			
		||||
			span.button-label-small Start the simple client
 | 
			
		||||
	br
 | 
			
		||||
	a(href="/bios")
 | 
			
		||||
		button.button-small
 | 
			
		||||
			span.button-label-small Start the repair tool
 | 
			
		||||
		Loading…
	
	Add table
		
		Reference in a new issue