• 工作日志,跨域和缓存的冲突问题


    记录和分享一篇工作中遇到的奇难杂症。一个前后端分离的项目,前端件图片上传到服务器上,存在跨域的问题。后端将图片返回给前端,并希望前端能对图片进行缓存。这是一个很常见的跨越和缓存的问题。可偏偏就能擦出意想不到的火花(据说和前端使用的框架有关)。

    跨域问题

    首先要解决跨域的问题。方法很简单,重写addCorsMappings方法即可。前端反馈跨域的问题虽然解决,但是静态资源返回的响应头是Cache-Control: no-cache ,导致资源文件加载速度较慢。

    处理跨域的代码

    override fun addCorsMappings(registry: CorsRegistry) {
        super.addCorsMappings(registry)
        registry.addMapping("/**")
        .allowedHeaders("*")
        .allowedMethods("POST","GET","DELETE","PUT")
        .allowedOrigins("*")
        .maxAge(3600)
    }
    

    处理后的响应头

    Access-Control-Allow-Headers: authorization
    Access-Control-Allow-Methods: POST,GET,DELETE,PUT
    Access-Control-Allow-Origin: *
    Access-Control-Max-Age: 3600
    Allow: GET, HEAD, POST, PUT, DELETE, TRACE, OPTIONS, PATCH
    Cache-Control: no-cache, no-store, max-age=0, must-revalidate
    

    静态资源配置

    然后再处理静态资源缓存的问题。方法也很简单,在资源映射的方法上加上.setCacheControl(CacheControl.maxAge(1, TimeUnit.DAYS)) 代码 。前端反馈缓存的问题虽然解决,但是静态资源跨域的问题又双叒叕出现了。

    处理静态资源代码

    override fun addResourceHandlers(registry: ResourceHandlerRegistry) {
        registry.addResourceHandler("/attachment/**")
        .addResourceLocations("file:$attachmentPath")
        .setCacheControl(CacheControl.maxAge(1, TimeUnit.DAYS))
    }
    

    经过反复的调试后发现,是setCacheControl方法导致静态资源的跨域配置失效。至于什么原因,看了源码,翻了资料都没有找到(可能是我找的不够认真)。更让人匪夷所思的是,火狐浏览器竟然是可以正常使用的。这让我排查问题的方向更乱了。但我也不能甩锅给浏览器啊!就在我快要下定决心甩锅给浏览器的时候,再次验证了“船到桥头自然直”的真谛。我抱着试一试的心态加了一个拦截器!

    解决方法

    到现在我还是不能很好地接受这个解决方法,我相信更好、更优雅地解决方法。目前的解决思路:既然返回的图片存在跨域和缓存的问题,那是否可以自定义拦截器,针对图片地址添加跨域和缓存的响应头呢?

    拦截器代码

    import org.springframework.stereotype.Component
    
    import javax.servlet.*
    import javax.servlet.http.HttpServletRequest
    import javax.servlet.http.HttpServletResponse
    import java.io.IOException
    
    @Component
    class CorsCacheFilter : Filter {
    
        @Throws(IOException::class, ServletException::class)
        override fun doFilter(req: ServletRequest, res: ServletResponse, chain: FilterChain) {
            val response = res as HttpServletResponse
            val request = req as HttpServletRequest
            if (request.requestURL.contains("/attachment/")) {
                response.addHeader("Access-Control-Allow-Origin", "*")
                response.addHeader("Access-Control-Allow-Credentials", "true")
                response.addHeader("Access-Control-Allow-Methods", "GET")
                response.addHeader("Access-Control-Allow-Headers", "*")
                response.addHeader("Access-Control-Max-Age", "3600")
                response.addHeader("Cache-Control", "max-age=86400")
            }
            chain.doFilter(req, res)
        }
    
        override fun init(filterConfig: FilterConfig) {}
        override fun destroy() {}
    }
    

    MVC配置代码

    import org.springframework.beans.factory.annotation.Value
    import org.springframework.context.annotation.Configuration
    import org.springframework.web.servlet.config.annotation.CorsRegistry
    import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry
    import org.springframework.web.servlet.config.annotation.WebMvcConfigurer
    
    @Configuration
    class WebMvcConfig : WebMvcConfigurer {
    
        @Value("${great.baos.attachment.path}")
        val attachmentPath: String = ""
    
        override fun addCorsMappings(registry: CorsRegistry) {
            super.addCorsMappings(registry)
            registry.addMapping("/**")
                    .allowedHeaders("*")
                    .allowedMethods("POST","GET","DELETE","PUT")
                    .allowedOrigins("*")
                    .maxAge(3600)
        }
    
        override fun addResourceHandlers(registry: ResourceHandlerRegistry) {
            registry.addResourceHandler("/attachment/**")
                    .addResourceLocations("file:$attachmentPath")
        }
    
    }
    

    处理后的响应头

    Accept-Ranges: bytes
    Access-Control-Allow-Credentials: true
    Access-Control-Allow-Headers: *
    Access-Control-Allow-Methods: GET
    Access-Control-Allow-Origin: *
    Access-Control-Max-Age: 3600
    Cache-Control: max-age=86400
    

    注意:

    一)、拦截器只能针对图片路径下的请求做处理

    二)、addResourceHandlers 方法不能再设置setCacheControl

    到这里,处理跨域和缓存冲突问题的其中一种解决方法就结束了。如果你也遇到了这样的问题,可以考虑try一try。

  • 相关阅读:
    javascript 中的暗物质 闭包
    关于使用 jBox 对话框的提交问题
    Orchard 的项目结构解决方案文件夹的原理与使用
    翻译:创建 Windows8 应用 Part I: Hello, world!
    翻译:FireBug 1.10 新特性
    SQL数据库设计经验
    我的女孩
    在WINDOWS下安装MRTG全攻略网络流量监控
    ASP实用函数库
    DIV CSS设计时IE6、IE7、FF 与兼容性有关的特性
  • 原文地址:https://www.cnblogs.com/itdragon/p/11068593.html
Copyright © 2020-2023  润新知