這是我在寫Plurk Hound時所遇到的問題。

Sinatra中,當client發出request,要求不存在於public directory下的檔案時,該如何實作呢?

就我最初所查到的資料來說,可以用下列這樣的作法來傳送位於其它位置的檔案給client:

1
2
3
get '/*' do |filename|
File.read(File.join('directory',filename))
end

用了之後發現,一般的HTML檔案的確是可以正常傳輸,可是所收到的HTML檔案render出來,上頭style全被脫光光了!
看到此處,想必大家的第一個念頭便是CSS出問題,但是在我輸入了相對應URL後仍是可以讀到CSS的內容。在看過header之後,才知道原來用這樣的讀取方式,Sinatra會將header內的Content-Type預設為text/html,瀏覽器當然也就不把它當作CSS來看了。

於是我馬上就想到了以下的work-around:

1
2
3
4
get '/*.css' do |filename|
content_type 'text/css'
File.read(File.join('directory',filename + '.css'))
end

上面的作法利用了Sinatra所提供的content_type helper來指定header內的Content-Type參數。但是如果要提供的檔案類型一多,每種類型都要單獨指定其Content-Type,光用膝蓋想就知道這不是個好主意。(就算你膝蓋中了一箭也是一樣)

在翻了一下Sinatra的source code之後,才發現原來Sinatra本身就有提供傳輸檔案的send_file helper,而且還會幫你處理Content-Type的問題,所以最好的solution其實是這樣:

1
2
3
get '/*' do |filename|
send_file(File.join('directory',filename))
end