在我的Sinatra项目中,我希望能够暂停错误代码和错误消息:
UIControl
我希望这反过来在错误页面模板中呈现(使用ERB)。例如:
halt 403, "Message!"
然而,显然error 403 do
erb :"errors/error", :locals => {:message => env['sinatra.error'].message}
end
(又名自述文件和每个网站都说我应该这样做)并不会暴露我提供的信息。 (此代码在运行时会返回env['sinatra.error'].message
错误。)
我已经搜索了4-5个小时并尝试了所有内容,但我无法弄清楚消息通过ERB呈现给我的位置!有谁知道它在哪里?
(似乎我能想到的唯一选择是写下这个而不是上面的undefined method `message' for nil:NilClass
代码,每次我想停止:
halt
此代码有效。但这是一个混乱的解决方案,因为它涉及硬编码错误ERB文件的位置。)
(如果您想知道,此问题与halt 403, erb(:"errors/error", :locals => {m: "Message!"})
配置标记无关,因为show_exceptions
和set :show_exceptions, false
都没有区别。)
答案 0 :(得分:6)
让我们看看Sinatra源代码,看看为什么这个问题不起作用。主要的Sinatra文件(lib/sinatra/base.rb
)只有2043行,并且代码非常可读!
所有halt
都是:
def halt(*response)
response = response.first if response.length == 1
throw :halt, response
end
例外情况包括:
# Dispatch a request with error handling.
def dispatch!
invoke do
static! if settings.static? && (request.get? || request.head?)
filter! :before
route!
end
rescue ::Exception => boom
invoke { handle_exception!(boom) }
[..]
end
def handle_exception!(boom)
@env['sinatra.error'] = boom
[..]
end
但由于某些原因,此代码永远不会运行(使用基本的“printf-debugging”进行测试)。这是因为在invoke
中块的运行方式如下:
# Run the block with 'throw :halt' support and apply result to the response.
def invoke
res = catch(:halt) { yield }
res = [res] if Fixnum === res or String === res
if Array === res and Fixnum === res.first
res = res.dup
status(res.shift)
body(res.pop)
headers(*res)
elsif res.respond_to? :each
body res
end
nil # avoid double setting the same response tuple twice
end
请注意catch(:halt)
。 if Array === res and Fixnum === res.first
部分是halt
设置的内容以及响应正文和状态代码的设置方式。
error 403 { .. }
块在call!
中运行:
invoke { error_block!(response.status) } unless @env['sinatra.error']
所以现在我们理解为什么这不起作用,我们可以寻找解决方案; - )
不是我能看到的。如果您查看invoke
方法的正文,您会看到在使用halt
时始终设置正文。您不希望这样,因为您想覆盖响应正文。
使用“真实”例外,而不是halt
“伪例外”。 Sinatra似乎没有预先定义的异常,但handle_exception!
确实会查看http_status
来设置正确的HTTP状态:
if boom.respond_to? :http_status
status(boom.http_status)
elsif settings.use_code? and boom.respond_to? :code and boom.code.between? 400, 599
status(boom.code)
else
status(500)
end
所以你可以使用这样的东西:
require 'sinatra'
class PermissionDenied < StandardError
def http_status; 403 end
end
get '/error' do
#halt 403, 'My special message to you!'
raise PermissionDenied, 'My special message to you!'
end
error 403 do
'Error message -> ' + @env['sinatra.error'].message
end
哪个按预期工作(输出为Error message -> My special message to you!
)。您可以在此处返回ERB模板。
答案 1 :(得分:0)
在Sinatra v2.0.7 +中,传递给halt
的消息存储在响应的正文中。因此,halt
带有错误代码和错误消息,例如:
halt 403, "Message!"
可以使用以下命令捕获并显示在错误页面模板中:
error 403 do
erb :"errors/error", locals: { message: body[0] }
end