This commit is contained in:
2025-11-28 16:23:32 +08:00
commit a9e0e16c29
826 changed files with 89805 additions and 0 deletions

View File

@@ -0,0 +1,34 @@
## 想法
暴露一些端点,提供一些功能。
1. http-cache
2. RateLimiter
3. ... ...
### 不是用网关,单体应用
拦截器处理,基于 redis 的 cache 时间或者 RateLimiter处理。
结构serviceName:http-cache:/user/1?queryString If-Modified-Since
结构serviceName:RateLimiter:/user/1 99
### 使用网关
将端点信息存储到 redis 里,供 网关使用。
结构serviceName:http-cache:endpoint:/user/{id} 100s
结构serviceName:RateLimiter:endpoint:/user/{id} 100/s
## RateLimiter Headers
```text
#=============================#===================================================#
# HTTP Header # Description #
#=============================#===================================================#
| X-RateLimit-Limit | Request limit per day / per 5 minutes |
+-----------------------------+---------------------------------------------------+
| X-RateLimit-Remaining | The number of requests left for the time window |
+-----------------------------+---------------------------------------------------+
| X-RateLimit-Reset | The remaining window before the rate limit resets |
| | in UTC epoch seconds |
+-----------------------------+---------------------------------------------------+
```

View File

@@ -0,0 +1,30 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<artifactId>BladeX-Tool</artifactId>
<groupId>org.springblade</groupId>
<version>${revision}</version>
</parent>
<artifactId>blade-starter-actuate</artifactId>
<name>${project.artifactId}</name>
<version>${project.parent.version}</version>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>org.springblade</groupId>
<artifactId>blade-core-tool</artifactId>
</dependency>
<!-- Auto -->
<dependency>
<groupId>org.springblade</groupId>
<artifactId>blade-core-auto</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,61 @@
/**
* BladeX Commercial License Agreement
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
* <p>
* Use of this software is governed by the Commercial License Agreement
* obtained after purchasing a license from BladeX.
* <p>
* 1. This software is for development use only under a valid license
* from BladeX.
* <p>
* 2. Redistribution of this software's source code to any third party
* without a commercial license is strictly prohibited.
* <p>
* 3. Licensees may copyright their own code but cannot use segments
* from this software for such purposes. Copyright of this software
* remains with BladeX.
* <p>
* Using this software signifies agreement to this License, and the software
* must not be used for illegal purposes.
* <p>
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
* not liable for any claims arising from secondary or illegal development.
* <p>
* Author: DreamLu (596392912@qq.com)
*/
package org.springblade.core.http.cache;
import lombok.Getter;
import lombok.Setter;
import org.springframework.boot.context.properties.ConfigurationProperties;
import java.util.ArrayList;
import java.util.List;
/**
* Http Cache 配置
*
* @author L.cm
*/
@ConfigurationProperties("blade.http.cache")
public class BladeHttpCacheProperties {
/**
* Http-cache 的 spring cache名默认bladeHttpCache
*/
@Getter
@Setter
private String cacheName = "bladeHttpCache";
/**
* 默认拦截/**
*/
@Getter
private final List<String> includePatterns = new ArrayList<String>() {{
add("/**");
}};
/**
* 默认排除静态文件目录
*/
@Getter
private final List<String> excludePatterns = new ArrayList<>();
}

View File

@@ -0,0 +1,63 @@
/**
* BladeX Commercial License Agreement
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
* <p>
* Use of this software is governed by the Commercial License Agreement
* obtained after purchasing a license from BladeX.
* <p>
* 1. This software is for development use only under a valid license
* from BladeX.
* <p>
* 2. Redistribution of this software's source code to any third party
* without a commercial license is strictly prohibited.
* <p>
* 3. Licensees may copyright their own code but cannot use segments
* from this software for such purposes. Copyright of this software
* remains with BladeX.
* <p>
* Using this software signifies agreement to this License, and the software
* must not be used for illegal purposes.
* <p>
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
* not liable for any claims arising from secondary or illegal development.
* <p>
* Author: DreamLu (596392912@qq.com)
*/
package org.springblade.core.http.cache;
import org.springframework.core.annotation.AliasFor;
import java.lang.annotation.*;
/**
* Http cache
* cache-control
* <p>
* max-age 大于0 时 直接从游览器缓存中 提取
* max-age 小于或等于0 时 向server 发送http 请求确认 ,该资源是否有修改
*
* @author L.cm
*/
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface HttpCacheAble {
/**
* 缓存的时间,默认0,单位秒
*
* @return {long}
*/
@AliasFor("maxAge")
long value();
/**
* 缓存的时间,默认0,单位秒
*
* @return {long}
*/
@AliasFor("value")
long maxAge() default 0;
}

View File

@@ -0,0 +1,76 @@
/**
* BladeX Commercial License Agreement
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
* <p>
* Use of this software is governed by the Commercial License Agreement
* obtained after purchasing a license from BladeX.
* <p>
* 1. This software is for development use only under a valid license
* from BladeX.
* <p>
* 2. Redistribution of this software's source code to any third party
* without a commercial license is strictly prohibited.
* <p>
* 3. Licensees may copyright their own code but cannot use segments
* from this software for such purposes. Copyright of this software
* remains with BladeX.
* <p>
* Using this software signifies agreement to this License, and the software
* must not be used for illegal purposes.
* <p>
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
* not liable for any claims arising from secondary or illegal development.
* <p>
* Author: DreamLu (596392912@qq.com)
*/
package org.springblade.core.http.cache;
import lombok.AllArgsConstructor;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.web.servlet.WebMvcProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cache.CacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.lang.NonNull;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import java.util.HashSet;
import java.util.Set;
/**
* Http Cache 配置
*
* @author L.cm
*/
@AutoConfiguration
@AllArgsConstructor
@EnableConfigurationProperties(BladeHttpCacheProperties.class)
@ConditionalOnProperty(value = "blade.http.cache.enabled", havingValue = "true")
public class HttpCacheConfiguration implements WebMvcConfigurer {
private static final String DEFAULT_STATIC_PATH_PATTERN = "/**";
private final WebMvcProperties webMvcProperties;
private final BladeHttpCacheProperties properties;
private final CacheManager cacheManager;
@Bean
public HttpCacheService httpCacheService() {
return new HttpCacheService(properties, cacheManager);
}
@Override
public void addInterceptors(@NonNull InterceptorRegistry registry) {
Set<String> excludePatterns = new HashSet<>(properties.getExcludePatterns());
String staticPathPattern = webMvcProperties.getStaticPathPattern();
// 如果静态 目录 不为 /**
if (!DEFAULT_STATIC_PATH_PATTERN.equals(staticPathPattern.trim())) {
excludePatterns.add(staticPathPattern);
}
HttpCacheInterceptor httpCacheInterceptor = new HttpCacheInterceptor(httpCacheService());
registry.addInterceptor(httpCacheInterceptor)
.addPathPatterns(properties.getIncludePatterns().toArray(new String[0]))
.excludePathPatterns(excludePatterns.toArray(new String[0]));
}
}

View File

@@ -0,0 +1,100 @@
/**
* BladeX Commercial License Agreement
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
* <p>
* Use of this software is governed by the Commercial License Agreement
* obtained after purchasing a license from BladeX.
* <p>
* 1. This software is for development use only under a valid license
* from BladeX.
* <p>
* 2. Redistribution of this software's source code to any third party
* without a commercial license is strictly prohibited.
* <p>
* 3. Licensees may copyright their own code but cannot use segments
* from this software for such purposes. Copyright of this software
* remains with BladeX.
* <p>
* Using this software signifies agreement to this License, and the software
* must not be used for illegal purposes.
* <p>
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
* not liable for any claims arising from secondary or illegal development.
* <p>
* Author: DreamLu (596392912@qq.com)
*/
package org.springblade.core.http.cache;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springblade.core.tool.utils.ClassUtil;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.lang.NonNull;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import java.time.Clock;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.TimeUnit;
/**
* Http cache拦截器
*
* @author L.cm
*/
@Slf4j
@AllArgsConstructor
public class HttpCacheInterceptor implements HandlerInterceptor {
private final HttpCacheService httpCacheService;
@Override
public boolean preHandle(@NonNull HttpServletRequest request, @NonNull HttpServletResponse response, @NonNull Object handler) throws Exception {
// 非控制器请求直接跳出
if (!(handler instanceof HandlerMethod handlerMethod)) {
return true;
}
// http cache 针对 HEAD 和 GET 请求
String method = request.getMethod();
HttpMethod httpMethod = HttpMethod.valueOf(method);
List<HttpMethod> allowList = Arrays.asList(HttpMethod.HEAD, HttpMethod.GET);
if (!allowList.contains(httpMethod)) {
return true;
}
// 处理HttpCacheAble
HttpCacheAble cacheAble = ClassUtil.getAnnotation(handlerMethod, HttpCacheAble.class);
if (cacheAble == null) {
return true;
}
// 最后修改时间
long ims = request.getDateHeader(HttpHeaders.IF_MODIFIED_SINCE);
long now = Clock.systemUTC().millis();
// 缓存时间,秒
long maxAge = cacheAble.maxAge();
// 缓存时间,毫秒
long maxAgeMicros = TimeUnit.SECONDS.toMillis(maxAge);
String cacheKey = request.getRequestURI() + "?" + request.getQueryString();
// 后端可控制http-cache超时
boolean hasCache = httpCacheService.get(cacheKey);
// 如果header头没有过期
if (hasCache && ims + maxAgeMicros > now) {
response.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
response.setHeader(HttpHeaders.CACHE_CONTROL, "max-age=" + maxAge);
response.addDateHeader(HttpHeaders.EXPIRES, ims + maxAgeMicros);
response.addDateHeader(HttpHeaders.LAST_MODIFIED, ims);
log.info("{} 304 {}", method, request.getRequestURI());
return false;
}
response.setHeader(HttpHeaders.CACHE_CONTROL, "max-age=" + maxAge);
response.addDateHeader(HttpHeaders.EXPIRES, now + maxAgeMicros);
response.addDateHeader(HttpHeaders.LAST_MODIFIED, now);
httpCacheService.set(cacheKey);
return true;
}
}

View File

@@ -0,0 +1,73 @@
/**
* BladeX Commercial License Agreement
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
* <p>
* Use of this software is governed by the Commercial License Agreement
* obtained after purchasing a license from BladeX.
* <p>
* 1. This software is for development use only under a valid license
* from BladeX.
* <p>
* 2. Redistribution of this software's source code to any third party
* without a commercial license is strictly prohibited.
* <p>
* 3. Licensees may copyright their own code but cannot use segments
* from this software for such purposes. Copyright of this software
* remains with BladeX.
* <p>
* Using this software signifies agreement to this License, and the software
* must not be used for illegal purposes.
* <p>
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
* not liable for any claims arising from secondary or illegal development.
* <p>
* Author: DreamLu (596392912@qq.com)
*/
package org.springblade.core.http.cache;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.util.Assert;
/**
* Http Cache 服务
*
* @author L.cm
*/
public class HttpCacheService implements InitializingBean {
private final BladeHttpCacheProperties properties;
private final CacheManager cacheManager;
private Cache cache;
public HttpCacheService(BladeHttpCacheProperties properties, CacheManager cacheManager) {
this.properties = properties;
this.cacheManager = cacheManager;
}
public boolean get(String key) {
Boolean result = cache.get(key, Boolean.class);
return Boolean.TRUE.equals(result);
}
public void set(String key) {
cache.put(key, Boolean.TRUE);
}
public void remove(String key) {
cache.evict(key);
}
public void clear() {
cache.clear();
}
@Override
public void afterPropertiesSet() throws Exception {
Assert.notNull(cacheManager, "cacheManager must not be null!");
String cacheName = properties.getCacheName();
this.cache = cacheManager.getCache(cacheName);
Assert.notNull(this.cache, "HttpCacheCache cacheName: " + cacheName + " is not config.");
}
}