这是在Sinatra。在我的"get"中,我创建了一个实例变量,它是从外部xml文件创建的nokogiri对象。我找到一个动词文件并解析nokogiri对象,以便进行页面布局。在我的post方法中,我需要访问相同的nokogiri对象(我可能多次返回post并可能修改nokogiri对象)。我的方法是在动词页面中设置一个隐藏变量,如下所示:
<input type="hidden" name="test" value= '<%= @test %>' >
然后在我的帖子中,我从该变量创建了一个nokogiri对象,如下所示:
@test = Nokogiri::XML(params["test"])
这看起来很笨拙,但我对这方面没有经验。无论如何,一切都很好,除了在某个地方,我在xml中嵌入的引号被弄乱了。例如,我的文件中的node是这样开始的:
<property name="blah" value='{"name:foo"}'> </property>
当我把我的post of params["test"]放进去时,我得到了这个:
<property name="blah" value="{"name:foo"}"> </property>
(单引号变成双引号),最后,在将其转换回nokogiri对象后,使用以下代码:
@test = Nokogiri::XML(params["test"])
我得到这个:
<property name="blah" value="{"/>name:foo"}"> </root>
是否有更好的方法来保留对对象的访问?如果没有,是否有一种方法来保留我嵌入的引号(我认为在erb文件中设置隐藏变量是它被破坏的地方)
总结
- 将Nokogiri文档缓存在常量中(例如散列或模块),该常量存在于请求中(在同一服务器运行中;见下文)。
- 只发送key到表单中的hash。
- 使用该键将文档从常量中取出。
package_32.xml
<packages><kittens in_box="true">32</kittens></packages>
cache_nokodocs.rb
require 'sinatra'
require 'nokogiri'
module NokoDocs
@docs_by_file = {}
def self.[](file)
@docs_by_file[file] ||= Nokogiri::XML(IO.read(file))
end
end
get "/xml/:doc" do
@doc = params['doc']
@xml = NokoDocs[@doc]
<<-ENDHTML
The XML starts with '#{@xml.root.name}'
<form method="post" action="/">
<input type="hidden" name="xml" value="#{@doc}">
<button type="submit">Go</button>
</form>
ENDHTML
end
post "/" do
@xml = NokoDocs[params['xml']]
@xml.to_s
end
使用<<p> /strong> C:>curl http://localhost:4567/xml/package_32.xml
The XML starts with 'packages'
<form method="post" action="/">
<input type="hidden" name="xml" value="package_32.xml">
<button type="submit">Go</button>
</form>
# simulate post that the web browser does from the command line
C:>curl -d xml="package_32.xml" http://localhost:4567/
<?xml version="1.0"?>
<packages>
<kittens in_box="true">32</kittens>
</packages>
任何用户第一次请求一个特定的XML文件时,它将被加载到哈希中;对该文件的后续请求将直接从哈希中获取它,并预先解析。
小心!
文档将不会在服务器的多个实例中缓存(例如,如果你在反向代理后面)。它们也不会在服务器重新启动时被缓存。然而,如果这些是磁盘上的静态文件,最坏的情况是特定的服务器会话在缓存它之前只需要重新创建一次Nokogiri文档。
使用磁盘上的文件名,然后让用户将其发回给您,这可能是一件非常非常危险的事情。相反,您可以在加载文档并使用它时创建一个自定义键或随机键。例如:
require 'digest' module NokoDocs @docs_by_file = {} def self.from_file(file) key = Digest::SHA1( file + rand(100) ) [ @docs_by_file[key] ||= Nokogiri::XML(IO.read(file)), key ] end def self.from_key(key) @docs_by_file[key] end end get "/xml/:doc" do @xml, @key = NokoDocs.from_file params['doc'] ... "<input type="hidden" name="key" value="#{@key}">" ... end post "/" do @xml = NokoDocs.from_key params['key'] end
这是一个潜在的内存泄漏。用户请求的每个唯一文档都被解析为一个大的Nokogiri文档,并永久保存(直到重新启动服务器)。您可能想要一个记录最后访问时间的系统,并有一个定时作业,定期清除一段时间未访问的项目。