从零搭建微服务项目Base(第7章——微服务网关模块基础实现)

前言:

在前面6章的学习中已经完成了服务间的调用实现,即各微服务通过nacos或eureka服务器完成服务的注册,并从nacos中拉取配置实现热更新。当某个服务接口需要调用其他服务时,通过feign定义接口,并通过注解配置服务名称,在nacos或eureka服务器中找到对应服务端口完成调用。

但实际应用中,用户不可能直接访问这些服务端口,因为每个服务对应一个端口,当服务拆分很多时,会有大量端口,前端开发人员不可能针对每次调用看文档找对应端口,因此引入网关模块,用户只需要访问网关模块端口,网关模块自动转发,且网关模块也能实现服务聚合、负载均衡、用户鉴权等功能。为此,本章实现基础的网关模块,包括网关服务模块创建、路由断言、过滤器配置

本章代码基于第6章项目,前置源码可在第6章博客下载,博客链接如下:

从零搭建微服务项目(第6章——Feign性能优化以及模块抽取)-CSDN博客https://blog.csdn.net/wlf2030/article/details/145649565简要介绍前置项目流程:order-service以及user-service两服务分别连接order-db以及user-db两数据库,order-db中仅有user-id,user-info存在user-db中,为提供完整order-info,order-service通过nacos发现user-service服务地址并使用Feign调用服务端口拿取user-info结合从order-db中拿取的信息返回给前端。同时项目自定义日志输出。

本项目源码链接如下:

wlf728050719/SpringCloudBase7https://github.com/wlf728050719/SpringCloudBase7以及本专栏会持续更新微服务项目,每一章的项目都会基于前一章项目进行功能的完善,欢迎小伙伴们关注!同时如果只是对单章感兴趣也不用从头看,只需下载前一章项目即可,每一章都会有前置项目准备部分,跟着操作就能实现上一章的最终效果,当然如果是一直跟着做可以直接跳过这一部分。


一、前置项目准备

1.从github下载前一章的项目解压,重命名为Base7打开。

2.重命名模块为Base7.

3.父工程pom.xml中<name>改成Base7。

4.选择环境为dev,并重新加载maven

5.启动nacos(安装和启动见第三章)

6.进入nacos网页 配置管理->配置列表确认有这些yaml文件。

(如果不是一直跟着专栏做自然是没有的,需要看第四章的环境隔离和配置拉取,记得把父工程pom文件中namespace的值与nacos中命名空间生成的保持一致)

7.配置数据源,更换两服务的resources下yml文件的数据库配置,数据库sql见第一章数据库准备部分。

.测试数据库连接 属性->点击数据源->测试连接->输入用户名密码

8.添加运行配置 服务->加号->运行配置类型->spring boot。

启动服务,测试接口。

能够在日志文件中看到最新的日志记录。


二、网关服务模块创建以及配置

1.新建SpringBoot模块,配置如下。

2.不添加任何依赖

3.删除不必要文件和目录,最终结构如下。

4.将gateway模块的pom文件替换为下面内容。

<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>cn.bit</groupId><artifactId>Base7</artifactId><version>1.0-SNAPSHOT</version><relativePath>../pom.xml</relativePath></parent><artifactId>gateway</artifactId><version>0.0.1-SNAPSHOT</version><name>gateway</name><description>gateway</description><dependencies><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-gateway</artifactId><version>2.2.5.RELEASE</version></dependency><!-- nacos客户端依赖包 --><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build></project>

4.修改父文件pom,即将gateway模块声明为父模块的子模块,重新加载maven模块。

5.重新加载maven文件后,查看maven结构是否如下,如果不是见本专栏第0章第三节部分有对应解决方法。

6.在父文件pom中为gateway在各配置环境下设置端口。

7.在gateway的application中排除默认数据源,否则需要在application中配置数据源,后续动态路由时需要使用数据库时再恢复。

8.为gateway在resources目录下创建application.yml配置文件,内容如下:

server:port: @gateway.port@
spring:application:name: gatewaycloud:nacos:server-addr: localhost:8848discovery:namespace: @namespace@gateway:routes:- id: user-serviceuri:lb://user-servicepredicates:- Path=/user/**- id: order-serviceuri:lb://order-servicepredicates:- Path=/order/**

9.启动服务

通过在网关端口输入路径即可通过断言调取对应服务的接口。


三、路由断言

目前是通过application.yml配置路由工厂。但使用动态路由需要重写实现路由工厂类,以及使用统一的格式便于规范数据库中路由信息,即使用args+name,为方便后续章节理解,使用args+name替换gateway的application.yml,内容如下:

server:port: @gateway.port@
spring:application:name: gatewaycloud:nacos:server-addr: localhost:8848discovery:namespace: @namespace@gateway:routes:- id: user-serviceuri:lb://user-servicepredicates:- name: Pathargs:_genkey_0: /user/**- id: order-serviceuri:lb://order-servicepredicates:- name: Pathargs:_genkey_0: /order/**

测试通过


四、路由过滤器

后续鉴权模块需要配合网关的过滤器一起搭配使用才能实现不同角色不同权限访问对应服务/端口,需要手写代码实现 AbstractGatewayFilterFactory,目前先通过yml配置文件为网关添加过滤器方便后续理解。

修改网关模块的yml文件如下:(现在的yml其实就已经很长了,后续必然需要使用代码结合数据库代替配置文件)

server:port: @gateway.port@
spring:application:name: gatewaycloud:nacos:server-addr: localhost:8848discovery:namespace: @namespace@gateway:routes:- id: user-serviceuri:lb://user-servicepredicates:- name: Pathargs:_genkey_0: /user/**filters:- name: AddRequestHeaderargs:name: sourcevalue: request user from gateway- id: order-serviceuri:lb://order-servicepredicates:- name: Pathargs:_genkey_0: /order/**filters:- name: AddRequestHeaderargs:name: sourcevalue: request order from gateway

为了获取请求头内容,对OrderController和UserController进行修改。直接替换成下面内容即可。

package cn.bit.orderservice.controller;import cn.bit.common.pojo.vo.OrderInfoVO;
import cn.bit.common.pojo.vo.R;
import cn.bit.orderservice.service.OrderService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;@Slf4j
@RestController
@RequestMapping("/order")
public class OrderController {@Autowiredprivate OrderService orderService;@GetMapping("/test/{id}")public String test(@PathVariable Integer id) {System.out.println(id);return id.toString();}@GetMapping("/info/{id}")public R getOrderInfoById(@PathVariable Integer id, @RequestHeader(value = "source",required = false) String source) {log.debug("debug");log.info("info");log.warn("warning");System.out.println(source);OrderInfoVO orderInfoVO = orderService.getOrderInfoById(id);if (orderInfoVO == null) {return R.failed("订单不存在");}elsereturn R.ok(orderInfoVO);}
}
package cn.bit.userservice.controller;import cn.bit.common.pojo.dto.UserBaseInfoDTO;
import cn.bit.common.pojo.vo.R;
import cn.bit.common.pojo.vo.UserFavorVO;
import cn.bit.userservice.config.PatternProperties;
import cn.bit.userservice.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;@RestController
@RequestMapping("/user")
public class UserController {@Autowiredprivate UserService userService;@Autowiredprivate PatternProperties patternProperties;@GetMapping("/test/{id}")public String test(@PathVariable Integer id) {System.out.println(id);return id.toString()+" "+LocalDateTime.now().format(DateTimeFormatter.ofPattern(patternProperties.getDateformat()));}@GetMapping("/favor/{id}")public R getUserFavorById(@PathVariable Integer id) {UserFavorVO vo = userService.getUserFavorById(id);if(vo != null) {return R.ok(vo);}elsereturn R.failed("用户不存在");}@GetMapping("/baseInfo/{id}")public R getUserBaseInfoById(@PathVariable Integer id, @RequestHeader(value = "source",required = false) String source) {System.out.println("get request");System.out.println(source);UserBaseInfoDTO dto = userService.getUserBaseInfoById(id);if(dto != null) {return R.ok(dto);}elsereturn R.failed("用户不存在");}
}

启动服务

先访问user接口即localhost:1233/user/baseInfo/1

能够验证确实添加了请求头

再访问order接口即localhost:1233/order/info/1

发现order-service获取到请求头,user-service为null,因为网关只对访问order-service的request添加了请求头,order-service之后使用feign访问的user-service,自然没有请求头。

为了实现调用朔源可以修改UserClient的接口方法

以及其调用

再次启动服务调用


五、全局过滤器

之前的过滤器为每个路由的过滤器,而全局过滤器无论使用哪条路由均需要使用。配置如下:

在网关模块创建filter包以及AuthorizeFilter类,内容如下:

package cn.bit.gateway.filter;import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.util.MultiValueMap;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;@Order(-1)
@Component
public class AuthorizeFilter implements GlobalFilter {@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {ServerHttpRequest request = exchange.getRequest();MultiValueMap<String, String> queryParams = request.getQueryParams();String token = queryParams.getFirst("token");if("admin".equals(token)) {return chain.filter(exchange);}exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);return exchange.getResponse().setComplete();}
}

重启后发现只有请求参数包含token字段且值为token才能访问对应服务。


六、过滤器执行顺序


最后:

黑马课程关于网关模块讲解还是比较浅显,和企业实际应用有较大出入,后续会研究动态路由实现以及鉴权模块,这两模块比较复杂所以后续更新会慢些。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/70307.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C# ConcurrentQueue 使用详解

总目录 前言 在C#多线程编程中&#xff0c;数据共享如同走钢丝——稍有不慎就会引发竞态条件&#xff08;Race Condition&#xff09;或死锁。传统Queue<T>在并发场景下需要手动加锁&#xff0c;而ConcurrentQueue<T>作为.NET Framework 4.0 引入的线程安全集合&a…

在Vue项目中使用three.js在前端页面展示PLY文件或STL文件

前言&#xff1a;这是一个3d打印局域网管理系统的需求 一、安装three.js three.js官网&#xff1a;https://threejs.org/docs/#manual/en/introduction/Installation 我用的是yarn,官网用的是npm 二、使用three.js 1.在script部分导入three.js import * as THREE from thr…

DeepSeek 助力 Vue 开发:打造丝滑的右键菜单(RightClickMenu)

前言&#xff1a;哈喽&#xff0c;大家好&#xff0c;今天给大家分享一篇文章&#xff01;并提供具体代码帮助大家深入理解&#xff0c;彻底掌握&#xff01;创作不易&#xff0c;如果能帮助到大家或者给大家一些灵感和启发&#xff0c;欢迎收藏关注哦 &#x1f495; 目录 Deep…

大数据学习(46) - Flink按键分区处理函数

&&大数据学习&& &#x1f525;系列专栏&#xff1a; &#x1f451;哲学语录: 承认自己的无知&#xff0c;乃是开启智慧的大门 &#x1f496;如果觉得博主的文章还不错的话&#xff0c;请点赞&#x1f44d;收藏⭐️留言&#x1f4dd;支持一下博主哦&#x1f91…

10分钟上手DeepSeek开发:SpringBoot + Vue2快速构建AI对话系统

作者&#xff1a;后端小肥肠 目录 1. 前言 为什么选择DeepSeek&#xff1f; 本文技术栈 2. 环境准备 2.1. 后端项目初始化 2.2. 前端项目初始化 3. 后端服务开发 3.1. 配置文件 3.2. 核心服务实现 4. 前端服务开发 4.1. 聊天组件ChatWindow.vue开发 5. 效果展示及源…

Transformer多头注意力并行计算原理与工业级实现:从数学推导到PyTorch工程优化

一、核心数学原理剖析 1.1 多头注意力矩阵分解 Q XW^Q ∈ R^{nd_k} K XW^K ∈ R^{nd_k} V XW^V ∈ R^{nd_v} 多头分解公式&#xff1a; head_i Attention(QW_i^Q, KW_i^K, VW_i^V) 其中 W_i^Q ∈ R^{d_kd_k/h}, W_i^K ∈ R^{d_kd_k/h}, W_i^V ∈ R^{d_vd_v/h} (h为头数…

通过监督微调提升多语言大语言模型性能

引言 澳鹏助力一家全球科技公司提升其大语言模型&#xff08;LLM&#xff09;的性能。通过提供结构化的人工反馈形式的大语言模型训练数据&#xff0c;让该模型在30多种语言、70多种方言中的表现得到优化。众包人员们进行多轮对话&#xff0c;并依据回复的相关性、连贯性、准确…

大数据开发治理平台~DataWorks(核心功能汇总)

目录 数据集成 功能概述 使用限制 功能相关补充说明 数据开发 功能概述 数据建模 功能概述 核心技术与架构 数据分析 功能概述 数据治理 数据地图 功能概述 数据质量 功能概述 数据治理资产 功能概述 使用限制 数据服务 功能概述 数据集成 DataWorks的数据…

用Nginx打造防盗链护盾

用Nginx打造防盗链护盾 一、你的网站正在"为他人做嫁衣"&#xff1f; 想象一下这个场景&#xff1a; 你精心拍摄的摄影作品、录制的课程视频、设计的原创素材&#xff0c;被其他网站直接盗用链接。 更气人的是——当用户在他们网站查看这些资源时&#xff0c;消耗的…

STM32 看门狗

目录 背景 独立看门狗&#xff08;IWDG&#xff09; 寄存器访问保护 窗口看门狗&#xff08;WWDG&#xff09; 程序 独立看门狗 设置独立看门狗程序 第一步、使能对独立看门狗寄存器的写操作 第二步、设置预分频和重装载值 第三步、喂狗 第四步、使能独立看门狗 喂狗…

Kubernetes的Ingress 资源是什么?

在Kubernetes中&#xff0c;Ingress资源是一种用于管理集群外部对内部服务访问的API对象&#xff0c;主要用于将不同的外部请求路由到集群内的不同服务&#xff0c;以下是关于它的详细介绍&#xff1a; 定义与作用 Ingress资源定义了从集群外部到内部服务的HTTP和HTTPS路由规…

vue3-03初学vue3中的配置项setup(Composition API (组合API组件中所用到的:数据、方法等,均要配置在setup中)

1.关于setup Vue3.0中一个新的配置项&#xff0c;值为一个函数.setup是所有Composition API (组合API)“表演的舞台”m组件中所用到的:数据、方法等等&#xff0c;均要配置在setup中。 2..setup函数使用 setup函数的两种返回值 1.若返回一个对象&#xff0c;则对象中的属性、…

【go语言规范】 使用函数式选项 Functional Options 模式处理可选配置

如何处理可选配置&#xff1f; Config Struct 方式 (config-struct/main.go) 这是最简单的方式&#xff0c;使用一个配置结构体&#xff1a; 定义了一个简单的 Config 结构体&#xff0c;包含 Port 字段创建服务器时直接传入配置对象优点&#xff1a;简单直接缺点&#xff1a…

leetcode 2585. 获得分数的方法数

题目如下 数据范围 莫要被困难的外衣骗了&#xff0c;本题就是有数量限制的完全背包问题。显然我们可以令 f(x,y)为当有x种题目时分数为y时的方法数 令某种题目的数量为k 那么方法数应该是 f(x,y) f(x - 1,y - k * (分值))其中(0 < k < 题目数量)通过代码 class So…

深入理解JavaScript中的异步编程与Promise

一、引言 在JavaScript的世界中&#xff0c;异步编程是一个核心概念&#xff0c;尤其是在处理网络请求、文件操作或任何可能阻塞主线程的任务时。本文将深入探讨JavaScript中的异步编程模型&#xff0c;特别是Promise对象的使用。 二、异步编程基础 2.1 什么是异步编程&…

VS Code 如何搭建C/C++开发环境

目录 1.VS Code是什么 2. VS Code的下载和安装 2.1 下载和安装 2.2.1 下载 2.2.2 安装 2.2 环境的介绍 2.3 安装中文插件 3. VS Code配置C/C开发环境 3.1 下载和配置MinGW-w64编译器套件 3.1.1 下载 3.1.2 配置 3.2 安装C/C插件 3.3 重启VSCode 4. 在VSCode上编写…

如何查询网站是否被百度蜘蛛收录?

一、使用site命令查询 这是最直接的方法。在百度搜索框中输入“site:你的网站域名”&#xff0c;例如“site:example.com”&#xff08;请将“example.com”替换为你实际的网站域名&#xff09;。如果搜索结果显示了你的网站页面&#xff0c;并且显示了收录的页面数量&#xf…

数仓搭建:DWS层(服务数据层)

DWS层示例: 搭建日主题宽表 需求 维度 步骤 在hive中建数据库dws >>建表 CREATE DATABASE if NOT EXISTS DWS; 建表sql CREATE TABLE yp_dws.dws_sale_daycount( --维度 city_id string COMMENT 城市id, city_name string COMMENT 城市name, trade_area_id string COMME…

伪类选择器

作用&#xff1a;选中特殊状态的元素 一、动态伪类 1. :link 超链接 未被访问 的状态。 2. :visited 超链接 访问过 的状态。 3. :hover 鼠标 悬停 在元素上的状态。 4. :active 元素 激活 的状态。 什么是激活&#xff1f; —— 按下鼠标不松开。 注意点&#xf…

Kubernetes:EKS 中 Istio Ingress Gateway 负载均衡器配置及常见问题解析

引言 在云原生时代&#xff0c;Kubernetes 已经成为容器编排的事实标准。AWS EKS (Elastic Kubernetes Service) 作为一项完全托管的 Kubernetes 服务&#xff0c;简化了在 AWS 上运行 Kubernetes 的复杂性。Istio 作为服务网格领域的佼佼者&#xff0c;为微服务提供了流量管理…