在看这一篇之前 我是建议大家先去了解一下Springcloud Gateway的原理解读 就是我这篇文章《【云原生】Spring Cloud Gateway的底层原理与实践方法探究》
前端部分
这边建议直接套chatWeb的模板 前端的实现不是这里的重点 当然有兴趣的同学可以去翻一下源码 我把连接放这了哈GitHub - SuSuZeer/chatgpt-web-with-recharge: 使用vue3搭建的chatgpt聊天页面 在此基础上接入后端 使用Spring Cloud Gateway作为网关 增加了token计量检测 可以在此基础上建立一个充值系统
后端部分
准备工作
- 安装和配置Java开发环境
- 安装和配置Java开发环境
- 首先,确保你的计算机已经安装了Java开发工具包(JDK)。你可以从官方网站(https://www.oracle.com/java/technologies/javase-jdk15-downloads.html)下载并安装JDK。
安装完成后,设置环境变量,以便Java开发工具包可以在计算机上被访问。在Windows系统上,可以按照以下步骤进行设置:
- 打开控制面板并选择"系统和安全"。
- 点击"系统",然后选择"高级系统设置"。
- 在"高级"选项卡下,点击"环境变量"按钮。
- 在"系统变量"部分,点击"新建"按钮。
- 输入"JAVA_HOME"作为变量名,并将变量值设置为JDK安装目录的路径(例如:C:\Program Files\Java\jdk-15)。
- 点击"确定"保存设置。
- 在MacOS或Linux系统上,可以使用命令行设置环境变量。例如,在MacOS上,可以在终端中输入以下命令:
export JAVA_HOME=/usr/lib/jvm/java-15-openjdk-amd64
- 创建Spring Boot项目
接下来,我们将使用Spring Initializr创建一个新的Spring Boot项目。打开你的文本编辑器,创建一个新的Java项目,并按照以下步骤进行设置:
- 访问Spring Initializr网站(https://start.spring.io/)。
- 在页面上选择所需的项目配置,包括构建工具(Maven或Gradle)、Spring Boot版本和项目元数据。
- 在"Dependencies"部分,搜索并添加所需的依赖,如Spring Web、Spring Data JPA等。
- 点击"Generate"按钮,下载生成的项目压缩文件。
- 解压缩项目文件后,你就拥有一个基本的Spring Boot项目结构,可以开始进行开发。
- 导入所需的依赖
在项目的pom.xml文件中,你可以添加所需的依赖。例如,如果你需要使用Spring Web框架,可以添加以下依赖:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency>
- 注册Open AI账号并获取API密钥
这里的话 最近注册比较 难 需要找好一点的魔法还要国外的接平台
因为 有的节点 太多人用 他就会崩
当然了 相信很多人已经注册了账号了 那就按照官方的指示获取APIKey即可
Spring Cloud Gateway入门
- 了解API网关的概念和作用
API网关是一个中间层,用于在后端服务和客户端之间提供统一的访问接口。它扮演着流量控制、安全认证、请求转发和协议转换等角色,简化了微服务架构中的复杂性。API网关可以集中处理共享的功能,如身份验证、授权、请求转发和负载均衡,从而减轻了后端服务的负担。
- 使用Spring Cloud Gateway进行基本的路由配置
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-gateway</artifactId> </dependency>
- 实现请求转发和负载均衡 下文细讲此处
与Open AI对接
使用Spring Boot调用Open AI的API
添加Spring Cloud Gateway依赖
在项目的pom.xml
文件中添加以下依赖:
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-gateway</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-gateway</artifactId> </dependency> <dependency> <groupId>com.openai</groupId> <artifactId>openai-java-sdk</artifactId> <version>1.0.0</version> </dependency>
创建并配置OpenAiGatewayConfig类。
import org.springframework.cloud.gateway.route.RouteLocator; import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.http.HttpMethod; @Configuration public class OpenAiGatewayConfig { private final OpenAiService openAiService; public OpenAiGatewayConfig(OpenAiService openAiService) { this.openAiService = openAiService; } @Bean public RouteLocator customRouteLocator(RouteLocatorBuilder builder) { return builder.routes() .route("openai_chat", r -> r.path("/openai/chat") .and() .method(HttpMethod.POST) .filters(f -> f.filter((exchange, chain) -> { // 获取请求参数,例如用户输入的对话消息 String message = exchange.getRequest().getBody().toString(); // 调用OpenAI API的Chat接口进行对话 String response = openAiService.chat(message); // 返回OpenAI API的响应给客户端 return exchange.getResponse().writeWith(Mono.just(exchange.getResponse().bufferFactory().wrap(response.getBytes()))); })) .uri("http://api.openai.com/v1/chat/completions") ) .build(); } }
创建了一个名为customRouteLocator的RouteLocator Bean,该Bean定义了一个路由规则,将请求路径为/openai/chat且HTTP方法为POST的请求转发到OpenAI API的Chat接口上。
创建OpenAiService类。
创建一个名为OpenAiService的服务类,用于与OpenAI API进行交互。示例代码如下:
import com.openai.OpenAiApi; import com.openai.model.ChatCompletionRequest; import com.openai.model.ChatCompletionResponse; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; @Service public class OpenAiService { @Value("${openai.api.key}") private String apiKey; public String chat(String message) { OpenAiApi openAiApi = new OpenAiApi(apiKey); ChatCompletionRequest request = new ChatCompletionRequest(); // 设置Chat接口所需的参数 // ... ChatCompletionResponse response = openAiApi.chatCompletion(request); // 处理Chat接口的响应,返回对话结果 // ... return response.getText(); } }
使用OpenAI Java SDK来与OpenAI API进行交互。在chat方法中,根据OpenAI API文档中Chat接口的要求,设置请求参数并调用Chat接口,然后处理响应并返回对话结果。
配置应用程序属性。
在application.properties(或application.yml)文件中,配置OpenAI API的密钥:openai.api.key=YOUR_OPENAI_API_KEY
启用Spring Cloud Gateway
在Spring Boot应用程序的入口类(例如BlogApplication.java)上添加@EnableGateway注解,以启用Spring Cloud Gateway。
import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.gateway.config.GatewayAutoConfiguration; import org.springframework.cloud.gateway.config.GatewayClassPathWarningAutoConfiguration; import org.springframework.cloud.gateway.config.GatewayReactiveLoadBalancerClientAutoConfiguration; @SpringBootApplication(exclude = { GatewayAutoConfiguration.class, GatewayClassPathWarningAutoConfiguration.class, GatewayReactiveLoadBalancerClientAutoConfiguration.class }) @EnableGateway public class BlogApplication { public static void main(String[] args) { SpringApplication.run(BlogApplication.class, args); } }
配置负载均衡
如果你希望实现负载均衡,可以在application.properties
文件中添加以下配置:
spring.cloud.gateway.discovery.locator.enabled=true
这将启用Spring Cloud Gateway与服务发现组件(如Eureka、Consul等)集成,以实现负载均衡。
发送请求到Spring Cloud Gateway
现在,你可以将请求发送到Spring Cloud Gateway的路由上,然后它会将请求转发到OpenAI的API。
准备一个Spring Boot控制器,用于处理与OpenAI相关的请求:
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpEntity; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.client.RestTemplate; @RestController public class OpenAIController { @Autowired private RestTemplate restTemplate; @PostMapping("/api/openai") public ResponseEntity<String> invokeOpenAI(@RequestBody String requestBody) { HttpHeaders headers = new HttpHeaders(); headers.set(HttpHeaders.CONTENT_TYPE, "application/json"); HttpEntity<String> requestEntity = new HttpEntity<>(requestBody, headers); return restTemplate.exchange("http://localhost:8080/api/openai", HttpMethod.POST, requestEntity, String.class); } }
在上面的代码中,我们使用RestTemplate
来发送请求到Spring Cloud Gateway的路由。Spring Cloud Gateway会将请求转发到OpenAI的API。这样就实现了基本的对话了!
利用Spring Cloud Gateway实现令牌记量和限制对话次数
创建TokenLimiterFilter类
首先,创建一个名为TokenLimiterFilter.java
的类,它将实现全局过滤器接口GlobalFilter
和Ordered
接口。
import org.springframework.cloud.gateway.filter.GatewayFilterChain; import org.springframework.cloud.gateway.filter.GlobalFilter; import org.springframework.core.Ordered; import org.springframework.http.HttpStatus; import org.springframework.http.server.reactive.ServerHttpRequest; import org.springframework.stereotype.Component; import org.springframework.web.server.ServerWebExchange; import reactor.core.publisher.Mono; @Component public class TokenLimiterFilter implements GlobalFilter, Ordered { private static final String API_KEY_HEADER = "X-API-Key"; private static final int MAX_REQUESTS_PER_MINUTE = 100; @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { ServerHttpRequest request = exchange.getRequest(); String apiKey = request.getHeaders().getFirst(API_KEY_HEADER); // 检查 API Key 是否有效 if (isValidApiKey(apiKey)) { // 检查对话次数是否超过限制 if (isWithinRateLimit(apiKey)) { // 更新对话次数计数器 updateRequestCount(apiKey); return chain.filter(exchange); } else { // 对话次数超过限制,返回错误响应 exchange.getResponse().setStatusCode(HttpStatus.TOO_MANY_REQUESTS); return exchange.getResponse().setComplete(); } } else { // 无效的 API Key,返回错误响应 exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED); return exchange.getResponse().setComplete(); } } private boolean isValidApiKey(String apiKey) { // 根据实际逻辑检查 API Key 的有效性 // 返回 true 表示 API Key 有效,返回 false 表示无效 return /* 根据实际逻辑进行判断 */; } private boolean isWithinRateLimit(String apiKey) { // 根据实际逻辑检查对话次数是否超过限制 // 返回 true 表示对话次数未超过限制,返回 false 表示超过限制 int requestCount = /* 根据实际逻辑获取对话次数 */; return requestCount < MAX_REQUESTS_PER_MINUTE; } private void updateRequestCount(String apiKey) { // 根据实际逻辑更新对话次数计数器 } @Override public int getOrder() { return Ordered.HIGHEST_PRECEDENCE; } }
在上面的代码中,我们实现了filter
方法,在该方法中执行了以下操作:
- 获取请求中的API Key。
- 检查API Key是否有效。
- 检查对话次数是否超过限制。
- 根据结果返回相应的响应给客户端。
启用TokenLimiterFilter
在Spring Boot应用程序的入口类(例如BlogApplication.java)上添加@EnableGateway注解,以启用Spring Cloud Gateway,并通过@ComponentScan注解扫描并启用TokenLimiterFilter。
import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.gateway.config.GatewayAutoConfiguration; import org.springframework.cloud.gateway.config.GatewayClassPathWarningAutoConfiguration; import org.springframework.cloud.gateway.config.GatewayReactiveLoadBalancerClientAutoConfiguration; import org.springframework.context.annotation.ComponentScan; import org.springframework.web.bind.annotation.RestController; @SpringBootApplication(exclude = { GatewayAutoConfiguration.class, GatewayClassPathWarningAutoConfiguration.class, GatewayReactiveLoadBalancerClientAutoConfiguration.class }) @EnableGateway @ComponentScan(basePackages = "com.example.gateway") @RestController public class BlogApplication { public static void main(String[] args) { SpringApplication.run(BlogApplication.class, args); } }
现在,当请求经过Spring Cloud Gateway时,它将拦截并使用TokenLimiterFilter
进行处理。在TokenLimiterFilter
中,就可以根据实际需求实现令牌记量和对话次数限制的逻辑!