工做日誌,跨域和緩存的衝突問題

記錄和分享一篇工做中遇到的奇難雜症。一個先後端分離的項目,前端件圖片上傳到服務器上,存在跨域的問題。後端將圖片返回給前端,並但願前端能對圖片進行緩存。這是一個很常見的跨越和緩存的問題。可恰恰就能擦出意想不到的火花(聽說和前端使用的框架有關)。html

跨域問題

首先要解決跨域的問題。方法很簡單,重寫addCorsMappings方法便可。前端反饋跨域的問題雖然解決,可是靜態資源返回的響應頭是Cache-Control: no-cache ,致使資源文件加載速度較慢。前端

處理跨域的代碼java

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

處理後的響應頭web

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)) 代碼 。前端反饋緩存的問題雖然解決,可是靜態資源跨域的問題又雙叒叕出現了。spring

處理靜態資源代碼後端

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。

相關文章
相關標籤/搜索