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