Rack::Static如何服务一个包含指纹值的资产文件(css, js等)文件,以便缓存它



在我的基于rack的应用程序中,我想服务CSS和JS,所以我使用Rack::Static中间件,如下所示:

config.ru

use Rack::Static, urls: ["/css" ], root: "public"
run MyApp
public文件夹结构:
public
css
application.min.css

根据https://github.com/rack/rack/blob/2.2.4/lib/rack/static.rb的Rack::Static实现(链接指的是我使用的机架版本中的代码,即2.2.4),默认情况下,Cache-Control头将不设置在响应。

但是如果我使用下面的配置

use Rack::Static, urls: ["/css" ], root: "public",
:header_rules => [
# Cache CSS/JS files, matching given regex in public caches (e.g. Rack::Cache) as well as in the browser. For e.g. myfile.1.2.1.css
#
[ /.(?:[1-9].[0-9].[0-9]).(?:css|js)z/, {'cache-Control' => 'public, max-age=60'} ]
]

然后我可以在响应头下看到以下标题Cache-Control: public, max-age=60,例如在Firefox的Web开发人员工具下的网络选项卡中。

现在我想使用指纹策略缓存该CSS文件,如下面的参考资料所示,我找到了

https://css-tricks.com/strategies-for-cache-busting-css/aa-changing-file-name

https://csswizardry.com/2019/03/cache-control-for-civilians/

所以在我的HTML页面中,我要让我的样式表名称包含指纹版本,例如如下

<head>
...
...
<link href="/css/application.min.<MY_ASSET_VERSION>.css" rel="stylesheet">
</head>

设置<MY_ASSET_VERSION>1.0.0

但是我不应该在我的public文件夹中有任何名为application.min.1.0.0.css的文件。这样命名只是为了触发缓存崩溃。那么我怎么做Rack::Static当文件css/application.min.css遇到路径/css/application.min.1.0.0.css时,为其提供服务?

我是否需要实现一个中间件,应该放在应用程序的中间件堆栈后Rack::Static?如果是,谁能帮我一个例子,因为我没有实现任何中间件。

或者,如果有其他标准的方法来满足手头的需求,请提出建议。

谢谢。

张贴下面的解决方案,我实现使用中间件,这是为我工作。

中间件)/custom_middleware util.rb

module CustomMiddleware
module Util
extend self
EXTENSIONS_OF_ASSETS_TO_BE_FINGER_PRINTED = /css|js/
ASSET_FINGER_PRINT_FORMAT_REGEX = /[1-9].[0-9].[0-9]/
FINGER_PRINTED_ASSET_NAME_MATCHER_REGEX = /.(?:#{ASSET_FINGER_PRINT_FORMAT_REGEX}).(?:#{EXTENSIONS_OF_ASSETS_TO_BE_FINGER_PRINTED})z/
ORIGINAL_ASSET_NAME_DETERMINER_FROM_FINGER_PRINTED_NAME_REGEX = /(.+).(?:#{ASSET_FINGER_PRINT_FORMAT_REGEX}).(#{EXTENSIONS_OF_ASSETS_TO_BE_FINGER_PRINTED})z/
def determine_original_asset_name(fingerprinted_asset_name:)
md = fingerprinted_asset_name.match(ORIGINAL_ASSET_NAME_DETERMINER_FROM_FINGER_PRINTED_NAME_REGEX)
return fingerprinted_asset_name if md.nil?
arr = md.captures
asset_file_name = arr[0]
asset_file_extension = arr[1]
asset_name = "#{asset_file_name}.#{asset_file_extension}"
asset_name
end
end
end

中间件)/custom_middleware fingerprinted_asset_name_modifier.rb

require_relative 'util'
module CustomMiddleware
class FingeprintedAssetNameModifier
def initialize(app)
@app = app
end
def call(env)
env_path_info_key = 'PATH_INFO'
orig_path = env[env_path_info_key]
modified_path = Util.determine_original_asset_name(fingerprinted_asset_name: orig_path)
if modified_path != orig_path
env.merge!(env_path_info_key => modified_path)
end
@app.call(env)
end
end
end

config.ru

require_relative "middlewares/custom_middleware/fingerprinted_asset_name_modifier"

use CustomMiddleware::FingeprintedAssetNameModifier
use Rack::Static, urls: ["/css", "/js" ], root: "public",
:header_rules => [
# Cache CSS/JS files in public caches (e.g. Rack::Cache) as well as in the browser. For e.g. myfile.css
[ %w(css js), {'cache-control' => 'public, max-age=60'} ]
]

run MyApp

当下列CSS文件包含在我的页面

时,使用上述解决方案
<head>
...
...
<link href="/css/application.min.1.0.0.css" rel="stylesheet">
</head>

application.min.1.0.0.css文件服务于我的文件在public/css/application.min.css和响应头Cache-Control: public, max-age=60设置意味着60秒后,如果application.min.1.0.0.css被重新请求,它将从我的应用程序服务,而不是从浏览器的缓存。

如果更改页面中的资产指纹,也在第一次请求资产的60秒内,如以下

<link href="/css/application.min.1.0.5.css" rel="stylesheet"> 

和重新加载页面,资源从我的应用程序提供,而不是从浏览器的缓存。

希望这对那些可能会提出类似问题帖子的需求的人有用。

谢谢。

相关内容

  • 没有找到相关文章

最新更新