带spring的静态资产缓存

yh2wf1be  于 2021-07-26  发布在  Java
关注(0)|答案(1)|浏览(303)

我正在开发一个web应用程序,并打算利用缓存资源所带来的性能提升,但它附带了一个重要的警告。每当我更新静态文件时,用户不会立即看到这些更改,因此必须禁用浏览器的缓存才能获取最新版本。为了解决这个问题,我决定添加静态资产版本控制。与以下代码一起工作。

@Override
public void addResourceHandlers(final ResourceHandlerRegistry registry) {
    registry.addResourceHandler("/**")
            .addResourceLocations("classpath:/static/")
            .setCacheControl(CacheControl.maxAge(365, TimeUnit.DAYS))
            .resourceChain(true)
            .addResolver(new VersionResourceResolver().addContentVersionStrategy("/**"))
            // Costume made transformer to handle JS imports
            .addTransformer(new JsLinkResourceTransformer())
            .addTransformer(new CssLinkResourceTransformer());
}

@Bean
public ResourceUrlEncodingFilter resourceUrlEncodingFilter() {
    return new ResourceUrlEncodingFilter();
}

除了一个简单的细节外,一切都如期进行。js导入仍在加载无版本的文件。比如说 import * from './myscrypt.js' ,无法正常工作。
为了避免新的警告,我必须实现自己的资源转换器。实现完成了它的工作,现在我的导入将获取正确的版本,如 import * from './myscript-149shdhgshs.js' . 后来,我以为一切都修好了,但又出现了一个新问题。下面是一个场景,它将使您更容易理解。
我加载一个包含 script.js 然后spring给我提供正确版本的文件 script-v1.js 之后, script-v1.js 从导入函数 myscript.js 浏览器将获取脚本的正确版本 myscript-v1.js 他们两个在本地缓存
我更新 myscript.js 制作新版本 myscript-v2.js 我重新加载了页面,但是自从 script-v1.js 存储在缓存中,我用旧的导入加载它 myscript-v1.js ,即使有新版本
我就是没办法让它工作。当然,我可以停止使用 js modules 而是一次加载所有脚本,但这不是我想要的解决方案。有什么解决办法吗 js module 使用spring进行版本控制?

km0tfn4u

km0tfn4u1#

我解决这个缓存版本的方法是使用app version。如果这个项目是建立在maven上的,我看到你在使用 classpath 静态文件解析的资源。每当对js文件有一个新的更改时,您将有一个新的构建,如果您可以更改每个构建的版本,下面是我的解决方法。
pom.xml文件

<version>0.1.0</version>
<build>
    <resources>
      <resource>
        <directory>src/main/resources</directory>
        <filtering>true</filtering>
      </resource>
</resources>

应用程序.yml

build:
  version: @project.version@

这将把版本从pom.xml推送到application.yml,包括ide上的dev和构建的jar
控制器
我用的是小胡子视图分解器。

@Controller
public class HelloController {

    @Value("${build.version}")
    private String version;

    private String encodedVersion;

    @PostConstruct
    public void setup() {
        encodedVersion = new String(Base64.getEncoder().encode(version.getBytes())).replace("=", "");
    }

    @RequestMapping("/home")
    public ModelAndView home() {
        ModelAndView mv = new ModelAndView();
        mv.setViewName("home.html");
        return mv;
    }

    @ModelAttribute("version")
    public String getVersion() {
        return encodedVersion;
    }

}

主页.html

<html>
<head>
  <script type="text/javascript" src="/pop.js?cache={{version}}"></script>
  <script type="text/javascript">
    window.version = "{{version}}" // in case you need this somewhere
  </script>
</head>
<body>
  <h1>Home1</h1>
  version: {{version}}
</body>
</html>

操作现有js文件

@Configuration
@AutoConfigureAfter(DispatcherServletAutoConfiguration.class)
public class Config implements WebMvcConfigurer {
    @Value("${build.version}")
    private String version;

    private String encodedVersion;

    @PostConstruct
    public void setup() {
        encodedVersion = new String(Base64.getEncoder().encode(version.getBytes())).replace("=", "");
    }

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/**").addResourceLocations("classpath:/static/").setCacheControl(CacheControl.maxAge(365, TimeUnit.DAYS)).resourceChain(true)
            .addResolver(new VersionResourceResolver().addContentVersionStrategy("/**"))
            .addTransformer(new ResourceTransformer() {
                @Override
                public Resource transform(HttpServletRequest request, Resource resource, ResourceTransformerChain transformerChain) throws IOException {
                    // Be aware of side effects changing line break
                    String result = new BufferedReader(new InputStreamReader(resource.getInputStream())).lines().collect(Collectors.joining("\n"));
                    result = result.replace("{{cacheVersion}}", encodedVersion);
                    return new TransformedResource(resource, result.getBytes());
                }
            });
    }

}

流行音乐.js

import mod1 from './mod1.js?cache={{cacheVersion}}';
function dis() {
  console.log("hello")  
}

因为版本添加为 ModelAttribute 它将在所有请求Map中可用。对于每一个版本,这将被更改,并且可以使用这个缓存版本变量来获取文件。

相关问题