基于spring gateway 的静态资源缓存实现
由于子项目比较多,子项目都是通过嵌套的方式实现的。就会导致子页面加载比较慢,影响客户体验。1、通过spring boot缓存实现静态资源缓存。2、在gateway过滤器,对静态资源进行缓存。实现思路(AI搜的--!
·
由于子项目比较多,子项目都是通过嵌套的方式实现的。就会导致子页面加载比较慢,影响客户体验
实现思路(AI搜的--!):
1、通过spring boot缓存实现静态资源缓存
2、在gateway过滤器,对静态资源进行缓存
直接上代码:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
package com.xxx.filter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.cache.support.SimpleValueWrapper;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.client.WebClient;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
import java.net.URI;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @author Wang
* 创建时间: 2023/11/15 10:19
* 功能描述:静态资源缓存
*/
@Slf4j
@Component
public class StaticResourceFilter implements GlobalFilter, Ordered {
private static final String STATIC_RESOURCE_PATTERN = "\\.(html|css|js|png|jpg|jpeg|gif|woff2|woff)$";
private final WebClient webClient;
private final CacheManager cacheManager;
List<String> synchronizedList = Collections.synchronizedList(new ArrayList<>());
public StaticResourceFilter(WebClient webClient, CacheManager cacheManager) {
this.webClient = webClient;
this.cacheManager = cacheManager;
}
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
ServerHttpRequest request = exchange.getRequest();
URI uriInfo = request.getURI();
String staticResourcePath = getUrl(uriInfo);
if (isStaticResource(staticResourcePath) && !synchronizedList.contains(staticResourcePath)) {
//Route route = exchange.getAttribute(ServerWebExchangeUtils.GATEWAY_ROUTE_ATTR);
String cacheKey = request.getURI().toString();
Cache cache = cacheManager.getCache("staticResources");
// 尝试从缓存中获取静态资源
Object cachedResource = cache.get(cacheKey);
if (cachedResource != null) {
if (cachedResource instanceof SimpleValueWrapper) {
cachedResource = ((SimpleValueWrapper) cachedResource).get();
}
// 如果缓存中存在,直接返回缓存的资源
ServerHttpResponse response = exchange.getResponse();
HttpHeaders headers = response.getHeaders();
String fileSuffix = staticResourcePath.replaceAll(".*(\\.[a-zA-Z0-9]+)$", "$1");
// 根据文件后缀设置MIME类型
switch (fileSuffix) {
case ".html":
headers.setContentType(MediaType.TEXT_HTML);
break;
case ".js":
headers.set(HttpHeaders.CONTENT_TYPE, "application/javascript");
break;
case ".css":
headers.set(HttpHeaders.CONTENT_TYPE, "text/css");
break;
case ".png":
headers.setContentType(MediaType.IMAGE_PNG);
break;
case ".jpg":
case ".jpeg":
headers.setContentType(MediaType.IMAGE_JPEG);
break;
case ".woff":
headers.set(HttpHeaders.CONTENT_TYPE, "application/font-woff");
break;
case ".woff2":
headers.set(HttpHeaders.CONTENT_TYPE, "application/font-woff2");
break;
case ".ttf":
headers.set(HttpHeaders.CONTENT_TYPE, "application/x-font-ttf");
break;
case ".eot":
headers.set(HttpHeaders.CONTENT_TYPE, "application/vnd.ms-fontobject");
break;
default:
headers.setContentType(MediaType.ALL);
break;
}
// 这里假设缓存的内容是字节数组,您可以根据实际情况进行调整
DataBuffer dataBuffer = response.bufferFactory().wrap((byte[]) cachedResource);
return response.writeWith(Mono.just(dataBuffer));
}
// 如果缓存不存在,则继续请求下游服务获取资源,并将其缓存起来
return chain.filter(exchange).then(Mono.fromRunnable(() -> {
getResourceFromDownstream(staticResourcePath, cacheKey, cache);
}));
}
// 继续处理其他过滤器或请求
return chain.filter(exchange);
}
@Override
public int getOrder() {
return Ordered.HIGHEST_PRECEDENCE;
}
/**
* 根据请求路径判断是否为静态资源请求
*
* @param staticResourcePath 请求路径
*/
private boolean isStaticResource(String staticResourcePath) {
Pattern pattern = Pattern.compile(STATIC_RESOURCE_PATTERN);
Matcher matcher = pattern.matcher(staticResourcePath);
return matcher.find();
}
/**
* 请求下游服务静态资源的方法,这里只是一个示例,您需要根据实际情况实现此方法
*
* @param cache 缓存
* @param staticResourcePath URL
* @param cacheKey 缓存Key
*/
private void getResourceFromDownstream(String staticResourcePath, String cacheKey, Cache cache) {
synchronizedList.add(staticResourcePath);
Mono<byte[]> mono = webClient.get().uri(staticResourcePath).retrieve().bodyToMono(byte[].class);
// 处理响应数据
mono.subscribe(res -> {
synchronizedList.remove(staticResourcePath);
cache.put(cacheKey, res);
}, error -> {
log.error("请求下游服务静态资源失败:{},\n错误详情:{}", staticResourcePath, error.toString());
});
}
/**
* 获取静态资源地址
*
* @param uri uri
* @return 静态资源地址
*/
private String getUrl(URI uri) {
String path = uri.getPath();
String host = uri.getHost();
int port = uri.getPort();
// 下游服务的地址是
String downstreamUrl = String.format("http://%s:%s%s", host, port, path);
return downstreamUrl;
}
}
更多推荐
已为社区贡献1条内容
所有评论(0)