Заставить Феникса отрендерить JSON ошибок - PullRequest
1 голос
/ 25 февраля 2020

Проблема с Phoenix, когда пользователь пытается перейти по маршруту API, который не существует. Похоже, что Phoenix пытается отрендерить «404. html» по умолчанию, что приводит к вызову функции «перехватить все» (которая возвращает карту), что приводит к ошибке, поскольку Phoenix пытается отрендерить JSON как * 1017. *.

** (UndefinedFunctionError) function Phoenix.HTML.Safe.to_iodata/1 is undefined (module Phoenix.HTML.Safe is not available)
        Phoenix.HTML.Safe.to_iodata(%{error: %{errors: ["An internal error has occurred. Our team has been notified."], message: "Internal Error"}})
        (phoenix) lib/phoenix/controller.ex:729: Phoenix.Controller.__put_render__/5
        (phoenix) lib/phoenix/endpoint/render_errors.ex:77: Phoenix.Endpoint.RenderErrors.instrument_render_and_send/5
        (phoenix) lib/phoenix/endpoint/render_errors.ex:62: Phoenix.Endpoint.RenderErrors.__catch__/5
        (phoenix) lib/phoenix/endpoint/cowboy2_handler.ex:42: Phoenix.Endpoint.Cowboy2Handler.init/4

Это функция рендеринга по умолчанию, которая в конечном итоге вызывается:

  def render(code, _assigns) do
    Logger.error("Error handler requested #{inspect code}. Please add support for that.")

    %{
      error: %{
        message: "Internal Error",
        errors: ["An internal error has occurred. Out team has been notified."]
      }
    }
  end

Я видел решение "set_format", которое было в предыдущем вопросе (здесь: { ссылка }) и, как утверждает пользователь, это выглядит немного странно, хотя, похоже, работает.

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

Моя конечная цель чтобы заставить Phoenix не хотеть отображать 404. html, скорее я хотел бы либо произвольно указать шаблон, либо, по крайней мере, сказать Phoenix, что он должен искать 404. json. В идеале, решение будет иметь широкое применение.

1 Ответ

1 голос
/ 25 февраля 2020

Ваш роутер просто штекер. Вы можете обрабатывать ошибки так же, как Plug.Router или любой другой плагин. В приведенном ниже примере кода не стесняйтесь заменить MyAppWeb именем вашего веб-модуля.

defmodule MyAppWeb.Router do
  use MyAppWeb, :router
  use Plug.ErrorHandler  #<-- Add this line

  # and implement the callback handle_errors/2
  defp handle_errors(conn, %{reason: %Phoenix.Router.NoRouteError{message: message}}) do
    conn |> json(%{error: message}) |> halt()
  end

  defp handle_errors(conn, _) do
    conn |> json(%{error: "unknown"}) |> halt()
  end

  ...
end

Обратите внимание, что вы можете вызывать все функции, доступные для контроллера, поскольку Phoenix.Controller - это импортируется, когда вы import MyAppWeb, :router. Вы можете увидеть это в исходном коде модуля MyAppWeb, обратите внимание на макрос __using__/1 и функцию router/0.

...