【问题标题】:Force Phoenix to render JSON errors强制 Phoenix 呈现 JSON 错误
【发布时间】:2020-07-10 19:25:46
【问题描述】:

当用户尝试访问不存在的 API 路由时,Phoenix 遇到了问题。 Phoenix 似乎希望在默认情况下呈现“404.html”,从而导致调用 catch all 渲染函数(返回地图),然后导致错误,因为 Phoenix 正在尝试将 JSON 呈现为 HTML。

** (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

我在上一个问题(此处:https://stackoverflow.com/a/39189452)中看到了“set_format”解决方案,并且,正如用户所说,这确实让人觉得有点笨拙,尽管它似乎确实有效。

我也知道我可以只指定一个接受 404.html 的渲染函数,但这也比我想要的更像是一个创可贴。

我的最终目标是让 Phoenix 不想渲染 404.html,而是我想任意指定模板,或者至少告诉 Phoenix 它应该寻找 404.json。理想情况下,该解决方案将是应用范围广泛的。

【问题讨论】:

    标签: elixir phoenix-framework


    【解决方案1】:

    您的路由器只是一个插头。您可以像Plug.Router 或任何插件一样处理错误。在下面的示例代码中,请随意将 MyAppWeb 替换为您的 Web 模块的名称。

    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

    【讨论】:

    • 有道理,但我觉得这仍然没有我想要的那么优雅。我想我希望有一个配置选项,它只是告诉 Phoenix 总是呈现 JSON,或者给它一个格式来呈现像“#{error_name}.json”。如果这不存在那太酷了,只是想检查一下。我确实有一个类似于你建议的解决方案。
    【解决方案2】:

    您应该配置您的端点以将错误呈现为 json:

    config :the_app, TheApp.Endpoint,
      render_errors: [view: TheApp.ErrorView, accepts: ~w(json), layout: false]
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-10-04
      • 2016-01-08
      • 1970-01-01
      相关资源
      最近更新 更多