halt 403,"Message!"
error 403 do erb :"errors/error",:locals => {:message => env['sinatra.error'].message} end
然而,显然env [‘sinatra.error’].message(又名自述文件和每个网站都说我应该这样做)并不会暴露我提供的信息. (此代码在运行时返回nil的未定义方法`message’:NilClass错误.)
我已经搜索了4-5个小时并尝试了所有内容,但我无法弄清楚消息通过ERB呈现给我的位置!有谁知道它在哪里?
(看起来我能想到的唯一选择是写这个而不是上面的停止代码,每次我想停止:
halt 403,erb(:"errors/error",:locals => {m: "Message!"})
这段代码有效.但这是一个混乱的解决方案,因为它涉及硬编码错误ERB文件的位置.)
(如果你想知道,这个问题与show_exceptions配置标志无关,因为set:show_exceptions,false和set:show_exceptions,:after_handler没有区别.)
解决方法
让我们看看Sinatra源代码,看看为什么这个问题不起作用.主要的Sinatra文件(lib/sinatra/base.rb
)只有2043行,并且代码相当可读!
所有停止的是:
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”测试).这是因为在调用块时运行如下:
# 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和Fixnum === res.first部分是停止设置以及响应主体和状态代码的设置方式.
invoke { error_block!(response.status) } unless @env['sinatra.error']
所以现在我们明白为什么这不起作用,我们可以寻找解决方案;-)
那么我可以用某种方式停止吗?
不是我能看到的.如果你看一下invoke方法的主体,你会发现在使用halt时总是设置了body.您不希望这样,因为您想要覆盖响应正文.
解
使用“真实”异常而不是暂停“伪异常”. 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