rails 4: пользовательские страницы ошибок для 404, 500 и откуда приходит сообщение об ошибке 500 по умолчанию?



В настоящее время в производстве я получаю этот текст:



500 Internal Server Error
If you are the administrator of this website, then please read this web application's
log file and/or the web server's log file to find out what went wrong.


нет html на этой странице ничего.



где находится этот код? У меня есть нет public / 500.HTML или что-нибудь в этом отношении.



в моих маршрутах у меня есть:



  get "/404", :to => "errors#error_404"
get "/422", :to => "errors#error_404"
get "/500", :to => "errors#error_500"
get "/505", :to => "errors#error_505"


ErrorsController:



class ErrorsController < ApplicationController

def sub_layout
"left"
end

def error_404
render :status => 404, :formats => [:html], :layout => "white", :sub_layout => "left"
end

def error_422
render :status => 422, :formats => [:html], :layout => "white", :sub_layout => "left"
end

def error_500
render :status => 500, :formats => [:html], :layout => "white", :sub_layout => "left"
end

def error_505
render :status => 505, :formats => [:html], :layout => "white", :sub_layout => "left"
end

end


как заставить его загружать мои пользовательские ошибки всегда? На некоторых ошибках он просто бросает этот 2-строчный текст, идущий где-то из ядра rails, я хочу, чтобы он взял мой обычай стилизованные страницы ошибок каждый раз! как? спасибо!

764   4  

4 ответов:

ошибка, которую вы испытываете, выбрасывается из

https://github.com/rails/rails/blob/4-0-stable/actionpack/lib/action_dispatch/middleware/show_exceptions.rb#L18-L22

это означает, что код, который ваши исключения спасают, сами выбрасывают исключения. Вы можете проверить свои журналы для текста:

Error during failsafe response:

чтобы определить, что исключения действительно происходят из и, таким образом, решить ваши проблема.

обновить 2018

наши exception_handler gem теперь считается самым популярным (Rails custom error pages) ↴

enter image description here enter image description here


Как Это Работает

все исключения Rails обрабатываются с помощью config.exceptions_app. Это назначается в config/application.rb или config/environments/*.rb файлы - это должно быть обратный вызов:

enter image description here

всякий раз, когда Rails попадает в ошибку, он вызывает ShowExceptions middleware. Это вызывает exception_app и посылает весь request (включая exception) к exceptions_app:

Middleware-Powered Exceptions

exceptions_app нужно передать ответ. Если нет, то failsafe загружено:

  # show_exceptions.rb#L38
  def render_exception(env, exception)
    wrapper = ExceptionWrapper.new(env, exception)
    status  = wrapper.status_code
    env["action_dispatch.exception"] = wrapper.exception
    env["PATH_INFO"] = "/#{status}"
    response = @exceptions_app.call(request.env) # => exceptions_app callback
    response[1]["X-Cascade"] == "pass" ? pass_response(status) : response
  rescue Exception => failsafe_error # => raised if exceptions_app false
    $stderr.puts "Error during failsafe response: #{failsafe_error}\n  #{failsafe_error.backtrace * "\n  "}"
    FAILSAFE_RESPONSE
  end

The failsafe это хранится как FAILSAFE_RESPONSE в верхней части ShowExceptions.


Пользовательские Страницы Ошибок

если вы хотите создать пользовательские страницы ошибок, вам нужно ввести свой собственный обратный вызов в config.exceptions_app. Это может быть сделано либо в приложении, либо с драгоценным камнем:

enter image description here

обратите внимание, как call метод используется-вот как работает обратный вызов. Рельсы (env) вызывается, когда запрос получен от Интернет; когда возникает исключение, env перешло к exceptions_app.

качество обработки исключений будет зависеть от того, как вы управляете env. Это важно; ссылка self.routes тут не переносите окружающую среду вперед.

лучший способ-обрабатывать исключения с помощью отдельного контроллера. Это позволяет обрабатывать запрос, как если бы это был просто другой вид, предоставляя доступ к layout и других компонентов (model / email).

--

здесь два способы обработки исключений:

  1. переопределение 404/500 маршруты
  2. вызов контроллера

наш драгоценный камень был разработан вокруг нашего controller - вызывается каждый раз exception поднимается. Это дает полное контроль над процессом исключения, что позволяет 100% фирменная макет:

enter image description here

ExceptionHandler в настоящее время является ведущим производством пользовательских страниц ошибок gem для рельсов.

поддержанный на сверх 3 лет, самый простой и самый сильный самоцвет исключения для рельсов. Он работает на 100% на Rails 5 и уже был загружен более 70 000 раз.


камень

последние ver 0.8.0.0 имеет следующие обновления:

  • пользовательские исключения
  • исключение "сопоставление" (выберите, какие исключения для обработки)
  • уведомления по электронной почте
  • модель backend
  • звездочки 4+ интеграция
  • Для RSpec Тестов
  • представления на основе локали

вы можете подробнее здесь.


Управление Исключениями Рельсов

если вы не заинтересовавшись драгоценным камнем, позвольте мне объяснить процесс:

все исключения Rails обрабатываются с помощью config.exceptions_app обратный. Это назначается в config/application.rb или config/environments/*.rb файлы - это должен быть обратный вызов:

enter image description here

всякий раз, когда исключение создается вашим приложением,ShowExceptions вызывается промежуточное программное обеспечение. Это промежуточное программное обеспечение создает исключение в request и переправляет его в config.exceptions_app обратный звонок.

по умолчанию config.exceptions_app указывает на маршрутах. Вот почему Rails поставляется с 404.html,500.html и 422.html на .

если вы хотите создать custom страницы исключений, вам нужно переопределить config.exceptions_app обратный вызов-передача ошибочного запроса соответствующему обработчику, будь то controller или route:

[[middleware ]]

два способа эффективно управлять либо отправить ошибочные запросы к маршрутам, или для вызова контроллера.

самый простой и наиболее распространенный способ-переадресация запроса на маршруты; к сожалению, это игнорирует запрос и мешает вам правильно детализировать исключения.

лучший способ-вызвать отдельный контроллер. Это позволит вам передать весь запрос, что позволит вам сохранить его, отправить его по электронной почте или сделать ряд других вещей.

--

400 / 500 Ошибки

рельсы только ответить с HTTP-допустимыми ошибками.

в то время как приложения исключение может отличаться, возвращаемый код состояния должны либо 40x или 50x. Это соответствует спецификации HTTP и изложено здесь

enter image description here

это означает, что независимо от того, какое решение обработки исключений вы используете / build, Rails должен вернуть 40x или 50x ошибки в браузере.

другими словами, пользовательские страницы ошибок имеют мало общего с тип исключения-больше, как вы ловите и обслуживаете ответ браузер.

по умолчанию Rails делает это с 404.html,422.html и 500.html файлы . Если вы хотите самостоятельно обработать поток исключений, вам необходимо удалить эти файлы и направляйте ошибочные запросы на свой собственный exceptions_app обратный.

это можно сделать с помощью тега routes или controller (что я сейчас объясню):


1. Маршруты

самый простой способ-позволить маршрутам справиться с этим.

этот метод раздут и требует использования нескольких действий. Также трудно управлять ответами.

в этом уроке объясняет:

enter image description here

это показывает, как заменить exceptions_app с маршрутами напрямую:

# config/application.rb
config.exceptions_app = self.routes

вот код, который у меня есть (Ruby 2.0.0, Rails 4.0):

Конфигурации

#config/application.rb
config.exceptions_app = self.routes

маршруты

#config/routes.rb
if Rails.env.production?
   get '404', to: 'application#page_not_found'
   get '422', to: 'application#server_error'
   get '500', to: 'application#server_error'
end

Контроллер Приложения

#controllers/application_controller.rb
def page_not_found
    respond_to do |format|
      format.html { render template: 'errors/not_found_error', layout: 'layouts/application', status: 404 }
      format.all  { render nothing: true, status: 404 }
    end
  end

  def server_error
    respond_to do |format|
      format.html { render template: 'errors/internal_server_error', layout: 'layouts/error', status: 500 }
      format.all  { render nothing: true, status: 500}
    end
  end

Ошибки Разметки (полностью статический-для сервера только ошибки)

#views/layouts/error.html.erb
<!DOCTYPE html>
<html>
<head>
  <title><%= action_name.titleize %> :: <%= site_name %></title>
  <%= csrf_meta_tags %>
  <style>
    body {
        background: #fff;
        font-family: Helvetica, Arial, Sans-Serif;
        font-size: 14px;
    }
    .error_container {
        display: block;
        margin: auto;
        margin: 10% auto 0 auto;
        width: 40%;
    }
    .error_container .error {
        display: block; 
        text-align: center;
    }
    .error_container .error img {
        display: block;
        margin: 0 auto 25px auto;
    }
    .error_container .message strong {
        font-weight: bold;
        color: #f00;
    }
  </style>
</head>
<body>

    <div class="error_container">
        <%= yield %>
    </div>

</body>
</html>

Вид Ошибки

#views/errors/not_found_error.html.erb    
<div class="error">
    <h2>Sorry, this page has moved, or doesn't exist!</h2>
</div>


#views/errors/internal_server_error.html.erb
<div class="error">
    <div class="message">
        <strong>Error!</strong>
        We're sorry, but our server is experiencing problems :(
    </div>
</div>

хотя многие предпочитают метод "маршрутов" для его простоты, он не является ни эффективным, ни модульным. Действительно, если ваше приложение имеет какое-либо подобие объектной ориентации, вы быстро отклоните его как хак.

A много более громкий способ-использовать пользовательский контроллер, чтобы поймать чистое исключение. Таким образом, вы можете построить поток в соответствии с вашим общая структура приложения:


2. Контроллер

другой вариант заключается в маршрутизации всех запросов к контроллеру.

это бесконечно более мощный, поскольку он позволяет вам взять запрос (исключение) и передать его в представления, управляя им в бэкэнде. Это позволит для подобных сохранения его в базе данных.

этой суть показывает как:

enter image description here

это означает, что мы можем подключиться к промежуточному программному обеспечению и передать весь запрос контроллер.

если этот контроллер поддерживается моделью и представлениями, мы можем извлечь его в драгоценный камень (что мы и сделали). Если вы хотите сделать это вручную, вот как:

--

Config

красота этого метода заключается в том, что он подключается непосредственно в config.exceptions_app. Это означает, что любое исключение может быть обработано изначально, что позволяет повысить эффективность. Чтобы убедиться, что это работает, вам нужно поместить следующий код в config/application.rb (exceptions_app работает только в production -development показывает ошибки):

#config/application.rb
config.exceptions_app = ->(env) { ExceptionController.action(:show).call(env) }

чтобы проверить, вы можете установить "локальные" запросы в false:

#config/environments/development.rb
config.consider_all_requests_local  = false # true

--

контроллер

следующим шагом является добавление exception контроллер. Хотя это может быть обработано в application_controller, это гораздо лучше добывать в свой собственный. Обратите внимание на звонок от application.rb--ExceptionController.action(:show):

#app/controllers/exception_controller.rb
class ExceptionController < ApplicationController

  #Response
  respond_to :html, :xml, :json

  #Dependencies
  before_action :status

  #Layout
  layout :layout_status

  ####################
  #      Action      #
  ####################

  #Show
  def show
    respond_with status: @status
  end

  ####################
  #   Dependencies   #
  ####################

  protected

  #Info
  def status
    @exception  = env['action_dispatch.exception']
    @status     = ActionDispatch::ExceptionWrapper.new(env, @exception).status_code
    @response   = ActionDispatch::ExceptionWrapper.rescue_responses[@exception.class.name]
  end

  #Format
  def details
    @details ||= {}.tap do |h|
      I18n.with_options scope: [:exception, :show, @response], exception_name: @exception.class.name, exception_message: @exception.message do |i18n|
        h[:name]    = i18n.t "#{@exception.class.name.underscore}.title", default: i18n.t(:title, default: @exception.class.name)
        h[:message] = i18n.t "#{@exception.class.name.underscore}.description", default: i18n.t(:description, default: @exception.message)
      end
    end
  end
  helper_method :details

  ####################
  #      Layout      #
  ####################

  private

  #Layout
  def layout_status
    @status.to_s == "404" ? "application" : "error"
  end

end

--

вид

есть два вида, чтобы добавить, чтобы получить эту работу.

первое-это exception/show вид, а во-вторых это layouts/error. Во-первых, чтобы дать exception_contoller#show вид, а второй для 500 внутренние ошибки сервера.

#app/views/exception/show.html.erb
<h1><%= details[:name]    %></h1>
<p><%=  details[:message] %></p>


#app/views/layouts/error.html.erb (for 500 internal server errors)
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
  <head>
    <title>Error</title>
    <style>
      html {
        height: 100%;
        background: #fff;
      }
      body {
        font-family: Helvetica, Arial, Sans-Serif;
        font-size: 14px;
      }
      .error_container {
        display: block;
        margin: auto;
        margin: 10% auto 0 auto;
        width: 40%;
      }
      .error_container .error {
        display: block;
        text-align: center;
      }
      .error_container .error img {
        display: block;
        margin: 0 auto 15px auto;
      }
      .error_container .message > * {
        display: block;
      }
      .error_container .message strong {
        font-weight: bold;
        color: #f00;
      }
    </style>
  </head>
  <body>
    <div class="error_container"><%= yield %></div>
  </body>
</html>

вывод

в исключение не имеет значения, как код ошибки.

когда Rails вызывает исключение, он назначает один из вышеперечисленных HTTP коды ответов. Они позволяют вашему браузеру определить, был ли запрос успешным.

при работе с исключениями, вы должны убедиться, что вы в состоянии обрабатывать 40* ошибки (которые обычно используют тот же макет, что и остальная часть вашего приложения) и 50* ошибки (которые понадобятся свои макет.)

в обоих случаях, вы будете лучше использовать отдельную exception контроллер, который позволит вам управлять exception как объект.

страницы ошибок в приложении должны быть максимально простыми. Та же рекомендация касается их оказания. Если ваше приложение возвращает 500 HTTP-код ответа, это означает, что все уже пошло не так. И есть вероятность, что вы не смогли отобразить страницу ошибки и отобразить ее пользователю.

В идеале страницы ошибок должны быть простым HTML, обслуживаемым непосредственно вашим веб-сервером, не задев сервер приложений.

говоря о рельсах реализации этой идеи. Он основан на использование конвейера активов для предварительной компиляции статических страниц HTML.

Сначала добавьте новый тип активов (Rails > 4.1):

# config/initializers/assets.rb

Rails.application.config.assets.precompile += %w(404.html 500.html)
Rails.application.config.assets.paths << Rails.root.join('app/assets/html')
Rails.application.config.assets.register_mime_type('text/html', '.html')

если используется механизм шаблонов (например, slim, haml), зарегистрируйте его через инициализатор:

# for Slim
Rails.application.assets.register_engine('.slim', Slim::Template)
# for Haml
Rails.application.assets.register_engine('.haml', Tilt::HamlTemplate)

теперь вы готовы создавать красивые страницы ошибок в каталоге app/assets/html с помощью ваш любимый шаблон двигателя и рельсы встроенный вид помощников.

советы по производству

на конвейере производственных активов добавляет дайджест скомпилированные активы и файлы хранятся в папке по умолчанию (обычно общие/общедоступные / активы на рабочем сервере). Вы можете использовать capistrano для копирования страниц ошибок в корень веб-сервера:

# config/deploy.rb
# Capistrano 3 only

namespace :deploy do
  desc 'Copy compiled error pages to public'
  task :copy_error_pages do
    on roles(:all) do
      %w(404 500).each do |page|
        page_glob = "#{current_path}/public/#{fetch(:assets_prefix)}/#{page}*.html"
        # copy newest asset
        asset_file = capture :ruby, %Q{-e "print Dir.glob('#{page_glob}').max_by { |file| File.mtime(file) }"}
        if asset_file
          execute :cp, "#{asset_file} #{current_path}/public/#{page}.html"
        else
          error "Error #{page} asset does not exist"
        end
      end
    end
  end
  after :finishing, :copy_error_pages
end

и последнее. Попросите веб-сервер использовать эти файлы для определенных кодов ошибок HTTP (пример конфигурации nginx):

error_page 500 502 503 504 /500.html;    
error_page 404 /404.html;

Звездочка 3 Обновление

для Звездочки 3 вам нужно что-то вроде этого (проверено с рельсами 5):

# config/environments/production.rb
config.assets.configure do |env|
  env.register_transformer 'text/slim', 'text/html', Slim::Template
  env.register_mime_type 'text/slim', extensions: ['.html']
  env.register_engine '.slim', Slim::Template
end

# config/initializers/assets.rb
Rails.application.config.assets.precompile += %w(404.html 500.html)
Rails.application.config.assets.paths << Rails.root.join('app/assets/html')

вот последнее и быстрое исправление для показа страницы custom 404_error.

  • добавить ниже строки развитие.РБ или производства.РБ в своем env.

config.exceptions_app = self.маршруты

config.consider_all_requests_local = false

  • удалить все RM public / {404,500,422}.HTML-код
  • создать 404.формат html.Эрб file in статический папка вашего проекта rails. Вы можете добавить свой собственный html здесь.(это будет использовать макет приложения, поэтому не беспокойтесь о содержании верхнего и нижнего колонтитулов)

Comments

    Ничего не найдено.