记录和分享一篇工做中遇到的奇难杂症。一个先后端分离的项目,前端件图片上传到服务器上,存在跨域的问题。后端将图片返回给前端,并但愿前端能对图片进行缓存。这是一个很常见的跨越和缓存的问题。可恰恰就能擦出意想不到的火花(听说和前端使用的框架有关)。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。