From 80b3b66829c0d0edbcd18f990c678a3df6960cfc Mon Sep 17 00:00:00 2001 From: "Juliy V. Chirkov" Date: Sat, 29 May 2021 05:15:10 +0300 Subject: [PATCH] NGINX JavaScript example provides two ways of handling autogenetated error_pages with multilingual support and customized html template --- conf/http/errorpages/errorpages.conf | 53 +++++++++ njs/http/errorpages/errorpages.definitions.js | 102 ++++++++++++++++++ njs/http/errorpages/errorpages.js | 42 ++++++++ njs/http/errorpages/errorpages.template.js | 59 ++++++++++ 4 files changed, 256 insertions(+) create mode 100644 conf/http/errorpages/errorpages.conf create mode 100644 njs/http/errorpages/errorpages.definitions.js create mode 100644 njs/http/errorpages/errorpages.js create mode 100644 njs/http/errorpages/errorpages.template.js diff --git a/conf/http/errorpages/errorpages.conf b/conf/http/errorpages/errorpages.conf new file mode 100644 index 0000000..28bc4b8 --- /dev/null +++ b/conf/http/errorpages/errorpages.conf @@ -0,0 +1,53 @@ +load_module modules/ngx_http_js_module.so; + +events { } + +http { + js_path /etc/nginx/njs/; + + js_import utils.js; + js_import http/errorpages/errorpages.js; + + js_set $badRequest errorpages.badRequest; + + map $http_user_agent $badBot { + "~badbot" 1; + default 0; + } + + if ($badBot) { + return 400 $badRequest; + } + + error_page 301 /request-status/301; + error_page 302 /request-status/302; + error_page 303 /request-status/303; + error_page 307 /request-status/307; + error_page 308 /request-status/308; + error_page 400 /request-status/400; + error_page 401 /request-status/401; + error_page 403 /request-status/403; + error_page 404 /request-status/404; + error_page 405 /request-status/405; + error_page 410 /request-status/410; + error_page 413 /request-status/413; + error_page 414 /request-status/414; + error_page 429 /request-status/429; + error_page 431 /request-status/431; + error_page 500 /request-status/500; + error_page 501 /request-status/501; + error_page 502 /request-status/502; + error_page 503 /request-status/503; + error_page 504 /request-status/504; + + server { + listen 80; + + location ~ "^/request-status/[0-9]{3}$" { + internal; + default_type text/html; + + js_content errorpages.response; + } + } +} diff --git a/njs/http/errorpages/errorpages.definitions.js b/njs/http/errorpages/errorpages.definitions.js new file mode 100644 index 0000000..6bde59e --- /dev/null +++ b/njs/http/errorpages/errorpages.definitions.js @@ -0,0 +1,102 @@ +export default { + '301' : { + en : 'Moved permanently', + uk : 'Сторінку перенесено', + ru : 'Страница перемещена' + }, + '302' : { + en : 'Found', + uk : 'Сторінку тимчасово перенесено', + ru : 'Страница временно перемещена' + }, + '303' : { + en : 'See other', + uk : 'Дивіться іншу сторінку', + ru : 'Смотрите другую страницу' + }, + '307' : { + en : 'Temporary redirect', + uk : 'Сторінку тимчасово перенесено', + ru : 'Страница временно перемещена' + }, + '308' : { + en : 'Permanent redirect', + uk : 'Сторінку перенесено', + ru : 'Страница перемещена' + }, + '400' : { + en : 'Bad request', + uk : 'Помилковий запит', + ru : 'Ошибочный запрос' + }, + '401' : { + en : 'Unauthorized', + uk : 'Авторизацію не пройдено', + ru : 'Требуется авторизация' + }, + '403' : { + en : 'Forbidden', + uk : 'Доступ заборонено', + ru : 'Доступ запрещен' + }, + '404' : { + en : 'Not found', + uk : 'Сторінку не знайдено', + ru : 'Страница не найдена' + }, + '405' : { + en : 'Method not allowed', + uk : 'Метод не підтримується', + ru : 'Метод не поддерживается' + }, + '410' : { + en : 'Gone', + uk : 'Сторінки не існує', + ru : 'Страницы не существует' + }, + '413' : { + en : 'Payload too large', + uk : 'Надто великий запит', + ru : 'Слишком большой запрос' + }, + '414' : { + en : 'URI too long', + uk : 'Надто довга адреса сторінки', + ru : 'Слишком длинный адрес страницы' + }, + '429' : { + en : 'Too many requests', + uk : 'Перевищено частоту запитів', + ru : 'Превышена частота запросов' + }, + '431' : { + en : 'Request header fields too large', + uk : 'Надто довгі заголовки у запиті', + ru : 'Слишком длинные заголовки в запросе' + }, + '500' : { + en : 'Internal server error', + uk : 'Внутрішня помилка сервера', + ru : 'Внутренняя ошибка сервера' + }, + '501' : { + en : 'Not implemented', + uk : 'Не підтримується', + ru : 'Не поддерживается' + }, + '502' : { + en : 'Bad gateway', + uk : 'Шлюз тимчасово недоступний', + ru : 'Шлюз временно недоступен' + }, + '503' : { + en : 'Service unavailable', + uk : 'Сервіс тимчасово недоступний', + ru : 'Сервис временно недоступен' + }, + '504' : { + en : 'Gateway timeout', + uk : 'Перевищено час очікування відповіді на шлюзі', + ru : 'Превышено время ожидания ответа на шлюзе' + } +} diff --git a/njs/http/errorpages/errorpages.js b/njs/http/errorpages/errorpages.js new file mode 100644 index 0000000..093cfbb --- /dev/null +++ b/njs/http/errorpages/errorpages.js @@ -0,0 +1,42 @@ +import pagehtml from 'errorpages.template.js' +import definitions from 'errorpages.definitions.js' + +function guessLang (request) { + var acceptLanguage = (request.headersIn['Accept-Language'] || '').split(',') + .map((elm) => elm.trim().slice(0, 2).toLowerCase()) + + var isUk = acceptLanguage.indexOf('uk') + var isRu = acceptLanguage.indexOf('ru') + var lang = 'en' + + if (isUk !== -1 || isRu !== -1) { + if (isUk !== -1 && isRu !== -1) { + lang = isUk < isRu ? 'uk' : 'ru' + } else { + lang = isUk === -1 ? 'ru' : 'uk' + } + } + + return lang +} + +function response (request) { + var status = request.uri.split('/').pop() + var html = '' + + if (Object.keys(definitions).includes(status)) { + var lang = guessLang(request) + + html = pagehtml(lang, status, definitions[status][lang]) + } + + request.return(200, html) +} + +function badRequest (request) { + var lang = guessLang(request) + + return pagehtml(lang, '400', definitions['400'][lang]) +} + +export default { response, badRequest } diff --git a/njs/http/errorpages/errorpages.template.js b/njs/http/errorpages/errorpages.template.js new file mode 100644 index 0000000..16dddb4 --- /dev/null +++ b/njs/http/errorpages/errorpages.template.js @@ -0,0 +1,59 @@ +export default (lang, status, description) => ` + + + + + + ${ status } ${ description } + + + + + ${ status } ${ description } + + +`