使用Sinatra提供XHTML服务

3
我正在创建一个Sinatra web应用程序,我希望所有的网页都能使用mime类型application/xhtml+xml进行服务。我正在使用Builder作为模板引擎。需要注意的是,该应用程序还将使用Builder模板引擎为各种AJAX API接口提供application/xml服务,以及使用scss模板引擎为text/css提供服务。
我注意到生成的网页会收到text/html的内容类型,而API接口则会收到application/xml的内容类型。然而,我不知道mime类型是如何决定的:是否存在html标签?是否使用布局?无论哪种情况,我都希望应用程序发出application/xhtml+xml的mime类型,而不是text/html的mime类型。
我知道可以通过content_type调用来指定mime类型,但我希望避免在每个路由函数中都需要这样做。是否有一种方法可以为给定的模板引擎设置默认的mime类型?或者mime类型是否可以由视图的文件名控制?Tilt是否提供了一种优雅的方式来控制mime类型?

Sinatra文档介绍了一种基于文件扩展名配置MIME类型的方法:Readme - Mime types。你可以潜在地使用before do块并以这种方式设置content_type,但我不确定这是否是实现此目的的最佳方法。 - Josh Voigts
除非您在某个地方特别更改它,否则使用Builder的所有请求都将具有application/xml作为内容类型。您是否有一个beforeafter块,在其中设置了content_type - matt
马特,这很有趣,因为我没有在任何地方更改它,但所有网页都会得到 text/html,而所有 AJAX 内容都会得到 application/xml。我确实希望一切都能得到 application/xml,但出于某种原因似乎并非如此... - wich
Josh,我看到了那个,但根据文件扩展名来确定MIME类型似乎只适用于静态文件和send_file函数,这是我从文档中了解到的。 - wich
@KonstantinHaase,就像我说的那样,这不是正在发生的事情。 - wich
显示剩余2条评论
1个回答

3
由于您的应用程序被分解为单独的对象,因此将所有AJAX路由提取到单独的Sinatra应用程序中应该很简单。这将允许您使用Sinatra的after hook。唯一的要求是您的AJAX调用必须具有标识它们为AJAX的内容;例如,通过将请求头设置为特殊值或使用特殊格式的路由。以下是唯一路由方法的示例rackup文件:
require 'sinatra/base'

class MainApp

  def get_info params
    # return some data structure
  end

end

class MainAppRoutes < Sinatra::Base

  def initialize mainapp
    super()
    @mainapp = mainapp
  end

  get '/' do # main page
    data = @mainapp.get_info(params)
    # render response from data
  end

end

class AjaxRoutes < Sinatra::Base

  def initialize mainapp
    super()
    @mainapp = mainapp
  end

  get '/getinfo' do # handler for /ajax/getinfo
    data = @mainapp.get_info(params)
    # generate XML response from data
  end

  after do
    content_type 'application/xml'
  end

end

mainapp = MainApp.new

map '/ajax' do
  run AjaxRoutes.new(mainapp)
end
run MainAppRoutes.new(mainapp)

在这个例子中,所有以/ajax开头的路由都由AjaxRoutes类的实例处理。after钩子确保这些响应的内容类型为“application/xml”。非ajax路由不受影响。
需要记住几件事情:
Rack::Builder.map会剥离它匹配的URL的部分。因此,在AjaxRoutes中'/'路由实际上会回答'/ajax/'的请求。
始终在Sinatra派生的端点类的初始化程序中调用super()。对于Sinatra中间件,请将第一个参数传递上去(Rack将使用下一个rack应用作为第一个参数调用#new)。
查看有关Sinatra filters的文档。使用after钩子修改响应时可能会出现潜在的令人沮丧的问题。

这对我有什么帮助?AJAX内容不是一个单独的应用程序。我有一个应用程序,它共享所需的数据在网页之间,包括AJAX内容和样式表,每个都应该给出自己的MIME类型。顺便说一下,AJAX内容应该是application/xml而不是application/xhtml+xml,后者是指网页。 - wich
2
一个应用程序是指Rack端点,它不是完全隔离的实体。如果您不了解Rack,并且无法从我上面概述的方法中推断出来,我很乐意删除我的回答。 - Catnapper
Catnapper,你能否提供一个更详细的例子来说明你的意思?我对Rack和Sinatra还不是很熟悉。 - wich
有很多方法可以解决这个问题,最好的方法取决于你正在做什么。应用程序结构很重要——业务逻辑是否全部包含在Sinatra路由代码中,还是分离到其他对象中?你是否在每个AJAX调用中设置请求头? - Catnapper
我正在尝试将所有业务代码分离成独立的对象,应用程序对象接收一些实例变量(@foo)以向模板通信数据,我没有在任何地方设置标题。 - wich
详细阐述基本方法 - 我认为单独的Sinatra应用程序是处理好因素化程序的方法。这种中间件版本也很有效。 - Catnapper

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接