spring 请求等问题
1.post请求 /*** @desc: (gateway主要接收前端请求 , 然后对请求的数据进行验证 , 验证之后请求反向代理到服务器 。*当请求 method 为 GET 时 , 可以顺利通过gateway 。 当请求 method 为 POST 时 , gateway则会报如下错误 。*java.lang.IllegalStateException : Only one connection receive subscriber allowed.*实际上spring - cloud - gateway反向代理的原理是 , 首先读取原请求的数据 , 然后构造一个新的请求 ,*将原请求的数据封装到新的请求中 , 然后再转发出去 。 然而我们在他封装之前读取了一次request body ,*而request body只能读取一次 。 因此就出现了上面的错误 。*解决方案 : 读取request body的时候 , 我们再封装一次request , 转发出去)*/ @Component public class PostFilter extends AbstractNameValueGatewayFilterFactory implements Ordered {@Overridepublic GatewayFilter apply(NameValueConfig nameValueConfig) {return (exchange, chain) -> {URI uri = exchange.getRequest().getURI();URI ex = UriComponentsBuilder.fromUri(uri).build(true).toUri();ServerHttpRequest request = exchange.getRequest().mutate().uri(ex).build();//封装我们的requestif ("POST".equalsIgnoreCase(request.getMethodValue())) {//判断是否为POST请求Flux<DataBuffer> body = request.getBody();AtomicReference<String> bodyRef = new AtomicReference<>();//缓存读取的request body信息body.subscribe(dataBuffer -> {CharBuffer charBuffer = StandardCharsets.UTF_8.decode(dataBuffer.asByteBuffer());DataBufferUtils.release(dataBuffer);bodyRef.set(charBuffer.toString());});//读取request body到缓存String bodyStr = bodyRef.get();//获取request bodyDataBuffer bodyDataBuffer = stringBuffer(bodyStr);Flux<DataBuffer> bodyFlux = Flux.just(bodyDataBuffer);request = new ServerHttpRequestDecorator(request) {@Overridepublic Flux<DataBuffer> getBody() {return bodyFlux;}};}return chain.filter(exchange.mutate().request(request).build());};}private DataBuffer stringBuffer(String value) {byte[] bytes = value.getBytes(StandardCharsets.UTF_8);NettyDataBufferFactory nettyDataBufferFactory = new NettyDataBufferFactory(ByteBufAllocator.DEFAULT);DataBuffer buffer = nettyDataBufferFactory.allocateBuffer(bytes.length);buffer.write(bytes);return buffer;}@Overridepublic int getOrder() {return -100;} }
2.网关
@Component @ConfigurationProperties("auth.skip.urls") @Getter @Setter @Slf4j public class AuthorizeFilter implements GlobalFilter, Ordered {/*** 令牌的名字*/private static final String AUTHORIZE_TOKEN = "Authorization";private static final String APP_KEY = "joe-plat-dest";/*** Jwt解析的key*/private static final String JWT_SECRET_KEY = "joemicroservice";/*** ACCESS_TOKEN key*/private final static String ACCESS_TOKEN_REDIS_KEY = "USER:ACCESS_TOKEN:userInfo:";private final static String ACCESS_TOKEN_USERID_REDIS_KEY = "USER:ACCESS_TOKEN:userId:";/*** redis中access_token过期时间*/private static final Long ACCESS_TOKEN_EXPIRE_TIME = 7 * 24 * 60 * 60 * 1000L;/*** 接口放行路径*/private String[] skipAuthUrls;@Autowiredprivate StringRedisTemplate stringRedisTemplate;/*** 服务名*/@Value("${spring.application.name}")private String applicationName;@Bean@ConditionalOnMissingBeanpublic HttpMessageConverters messageConverters(ObjectProvider<HttpMessageConverter<?>> converters) {return new HttpMessageConverters(converters.orderedStream().collect(Collectors.toList()));}/*** 全局拦截** @param exchange* @param chain* @return*/@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {val traceId = UUID.randomUUID().toString().replace("-", "");MDC.put("traceId", traceId);MDC.put("requestId", UUID.randomUUID().toString().replace("-", ""));Object uriObj = exchange.getAttributes().get(GATEWAY_REQUEST_URL_ATTR);if (uriObj != null) {URI uri = (URI) uriObj;uri = this.upgradeConnection(uri, "http");exchange.getAttributes().put(GATEWAY_REQUEST_URL_ATTR, uri);}ServerHttpRequest request = exchange.getRequest();ServerHttpResponse response = exchange.getResponse();String url = exchange.getRequest().getURI().getPath();if (!(url.startsWith("berData") || url.endsWith("/push"))) {log.info("接受到的url路径为:" + url);}StringBuffer sb = new StringBuffer();String urlPrefix = sb.append("/").append(applicationName).toString();if (url.startsWith(urlPrefix)) {url = url.substring(applicationName.length() + 1);log.info("截取到的url路径为:" + url);}//跳过不需要验证的路径if (checkSkipAuthUrls(Arrays.asList(skipAuthUrls), url)) {return chain.filter(exchange.mutate().request(exchange.getRequest().mutate().header("X-TraceId", traceId).build()).build());}//获取用户令牌信息//头文件中log.info("-----------------------获取请求头中的令牌---------------------");final String token = request.getHeaders().getFirst(AUTHORIZE_TOKEN);final String appId = request.getHeaders().getFirst(APP_KEY);//如果没有令牌,则拦截if (StringUtils.isEmpty(token)) {log.info("-----------------------未获取到token令牌---------------------");//设置没有权限的状态码401return unAuth(exchange, "登录失效,请重新登录", null);}//如果有令牌,则检验令牌是否有效try {String accessTokenRedisKey = ACCESS_TOKEN_USERID_REDIS_KEY + token;Boolean isExistKey = stringRedisTemplate.hasKey(accessTokenRedisKey);String redisKey = ACCESS_TOKEN_REDIS_KEY + token;Boolean isExistFlag = stringRedisTemplate.hasKey(redisKey);if (BooleanUtils.isTrue(isExistKey) || BooleanUtils.isTrue(isExistFlag)) {//判断用户是否有效,如果无效,返回指定状态码,跳出登陆if (Boolean.FALSE.equals(stringRedisTemplate.hasKey(ACCESS_TOKEN_USERID_REDIS_KEY + token))) {log.info("客户登陆状态无效,返回401");return unAuth(exchange, "登录失效,请重新登录", null);}if (BooleanUtils.isFalse(JwtUtils.validateToken(token))) {log.info("客户登陆状态无效,返回403");return unAuth(exchange, "登录失效,请重新登录", 403);} // stringRedisTemplate.expire(accessTokenRedisKey, ACCESS_TOKEN_EXPIRE_TIME, TimeUnit.MILLISECONDS); // stringRedisTemplate.expire(redisKey, ACCESS_TOKEN_EXPIRE_TIME, TimeUnit.MILLISECONDS);} else {return unAuth(exchange, "登录失效,请重新登录", null);}} catch (Exception e) {log.error("客户登陆失败, e:", e);return unAuth(exchange, "登录失效,请重新登录", null);}//将令牌封装到头文件中Consumer<HttpHeaders> httpHeaders = httpHeader -> {httpHeader.set(AUTHORIZE_TOKEN, token);httpHeader.set(APP_KEY, appId);};ServerHttpRequest serverHttpRequest = exchange.getRequest().mutate().headers(httpHeaders).build();exchange.mutate().request(serverHttpRequest).build();//有效,放行return chain.filter(exchange.mutate().request(exchange.getRequest().mutate().header("X-TraceId", traceId).build()).build());}private Boolean checkSkipAuthUrls(List<String> skipAuthUrls, String url) {if (skipAuthUrls.contains(url)) {return true;}List<String> superSkipUrlList = skipAuthUrls.stream().filter(x -> x.contains("**")).collect(Collectors.toList());if (!CollectionUtils.isEmpty(superSkipUrlList)) {for (String x : superSkipUrlList) {if (url.startsWith(x.substring(0, x.indexOf("**")))) {return true;}}}return false;}private Mono<Void> unAuth(ServerWebExchange exchange, String msg, Integer errCode) {ServerHttpResponse response = exchange.getResponse();response.getHeaders().setContentType(MediaType.APPLICATION_JSON);response.setStatusCode(HttpStatus.OK);log.error("[鉴权异常处理]请求路径:{} ,状态码:{}", exchange.getRequest().getPath(),errCode == null ? HttpStatus.UNAUTHORIZED.value() : errCode);return response.writeWith(Mono.fromSupplier(() -> {DataBufferFactory bufferFactory = response.bufferFactory();return bufferFactory.wrap(JSON.toJSONBytes(ResponseResult.fail(errCode == null ? HttpStatus.UNAUTHORIZED.value() : errCode, msg)));}));}@Overridepublic int getOrder() {return 0;}private URI upgradeConnection(URI uri, String scheme) {UriComponentsBuilder uriComponentsBuilder = UriComponentsBuilder.fromUri(uri).scheme(scheme);if (uri.getRawQuery() != null) {uriComponentsBuilder.replaceQuery(uri.getRawQuery().replace("+", "%20"));}return uriComponentsBuilder.build(true).toUri();}}
相关文章:

spring 请求等问题
1.post请求 /*** desc: (gateway主要接收前端请求 , 然后对请求的数据进行验证 , 验证之后请求反向代理到服务器 。*当请求 method 为 GET 时 , 可以顺利通过gateway 。 当请求 method 为 POST 时 , gateway则会报如下错误 。*jav…...

汽车制造行业,配电柜如何实施监控?
工业领域的生产过程依赖于高效、稳定的电力供应,而配电柜作为电力分配和控制的关键组件,其监控显得尤为重要。 配电柜监控通过实时监测、数据收集和远程控制,为工业企业提供了一种有效管理电能的手段,从而确保生产的连续性、安全性…...

stable diffusion实践操作-VAE
本文专门开一节写图生图相关的内容,在看之前,可以同步关注: stable diffusion实践操作 大部分底模有VAE,但是部分底模没有VAE,需要专门下载VAE才能使用。 最常用的VAE:vae-ft-mse-840000-ema-pruned 用来饱…...

《Flink学习笔记》——第一章 概念及背景
什么是批处理和流处理,然后由传统数据处理架构为背景引出什么是有状态的流处理,为什么需要流处理,而什么又是有状态的流处理。进而再讲解流处理的发展和演变。而Flink作为新一代的流处理器,它有什么优势?它的相关背…...

顺序表链表OJ题(2)->【数据结构】
W...Y的主页 😊 代码仓库分享 💕 前言: 单链表的结构常常不完美,没有双向链表那么”优秀“,所以繁衍出很多OJ练习题。今天我们继续来look look数据结构习题。 下面就是OJ时间!!! …...

css3有哪些新特性?(包含哪些模块)
css3有哪些新特性?包含哪些模块?以下是整理的21个css3新特性: 1.新增选择器 p:nth-child(n){color: rgba(255, 0, 0, 0.75)} 2.新增伪元素 ::before 和 ::after 3.弹性盒模型 display: flex; 4.多列布局 column-count: 5; 5.媒体查询 media (max-width:…...

【Grasshopper基础15】“右键菜单似乎不太对劲”
距离上一篇文章已经过去了挺久的,很长时间没有写GH基础部分的内容了,原因其一是本职工作太忙了,进度也有些落后,白天工作累成马,回家只想躺着;其二则是感觉GH基础系列基本上也介绍得差不多了,电…...

华为Mate60低调发布,你所不知道的高调真相?
华为Mate60 pro 这两天的劲爆新闻想必各位早已知晓,那就是华为Mate60真的来了!!!并且此款手机搭载了最新国产麒麟9000s芯片,该芯片重新定义了手机性能的巅峰。不仅在Geekbench测试中表现出色,还在实际应用…...

C++(18):命名空间
多个库将名字放置在全局命名空间中将引发命名空间污染。 命名空间可以用来防止名字冲突,它分割了全局命名空间,其中每个命名空间是一个作用域。通过在某个命名空间中定义库的名字,库的作者(以及用户)可以避免全局名字…...

K8S最新版本集群部署(v1.28) + 容器引擎Docker部署(上)
温故知新 📚第一章 前言📗背景📗目的📗总体方向 📚第二章 基本环境信息📗机器信息📗软件信息📗部署用户kubernetes 📚第三章 Kubernetes各组件部署📗安装kube…...

生产环境部署与协同开发 Git
目录 一、前言——Git概述 1.1 Git是什么 1.2 为什么要使用Git 什么是版本控制系统 1.3 Git和SVN对比 SVN集中式 Git分布式 1.4 Git工作流程 四个工作区域 工作流程 1.5 Git下载安装 1.6 环境配置 设置用户信息 查看配置信息 二、git基础 2.1 本地初始化仓库 编辑…...

Qt/C++编写视频监控系统80-远程回放视频流
一、前言 远程回放NVR或者服务器上的视频文件,一般有三种方式,第一种是调用厂家的SDK,这个功能最全,但是缺点明显就是每个厂家的设备都有自己的SDK,只兼容自家的设备,如果你的软件需要接入多个厂家的&…...

用于设计和分析具有恒定近心点半径的低推力螺旋轨迹研究(Matlab代码实现)
💥💥💞💞欢迎来到本博客❤️❤️💥💥 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密,逻辑清晰,为了方便读者。 ⛳️座右铭&a…...

MongoDB - 构造复杂查询条件执行查询
文章目录 1. 构造 keyword 的查询条件2. 构造 threatSubType 的查询条件3. 相应的实体类 /*** 查询白名单详情** param offset 第几页开始* param limit 每页显示的最大值* param keyword 模糊搜索值* param order 排序方式(升序/降序…...

如何从ChatGPT中获得最佳聊天对话效果
从了解ChatGPT工作原理开始,然后从互动中学习,这是一位AI研究员的建议。 人们利用ChatGPT来撰写文章、论文、生成文案和计算机代码,或者仅仅作为学习或研究工具。然而,大多数人不了解它的工作原理或它能做什么,所以他…...

深入浅出:手把手教你实现单链表
一、什么是链表 链表是一种链状数据结构。简单来说,要存储的数据在内存中分别独立存放,它们之间通过某种方式相互关联。 如果我们使用C语言来实现链表,需要声明一个结构体作为链表的结点,结点之间使用指针关联。 二、单向链表的结…...

vite 打包项目后访问显示空白页的问题,开发环境正常,生产环境无报错。
有没有可能, 你跟我遇到同样的问题 白屏的写法 const routes [{path: /,component: import(../views/index.vue),} ]正确的写法 const routes [{path: /,component: () > import(../views/index.vue),} ]有时候方向很重要,当在错误的方向上无脑冲…...

打造成功的砍价营销大解析,销量飙升
砍价活动是吸引顾客的一种有效方式,可以帮助提高销量和提升品牌知名度。在乔拓云平台上,我们提供了一套简单易用的工具,让您能够轻松地制作一个成功的砍价活动。下面,我将详细介绍具体步骤,让您能够轻松上手。 第一步&…...

【Flink进阶】- Flink kubernetes operator 常用的命令
目录 1、应用程序管理 (1)提交 Flink 应用程序 (2)查看 Flink 应用程序列表...

ASP.NET Core 的日志系统
ASP.NET Core 提供了丰富日志系统。 可以通过多种途径输出日志,以满足不同的场景,内置的几个日志系统包括: Console,输出到控制台,用于调试,在产品环境可能会影响性能。Debug,输出到 System.Di…...

android13(T) 以太网设置工具类
13 版本的以太网设置和以前版本有所变动,在 AS 中就能直接调用对应 API 将 build.gradle 版本修改 compileSdkVersion 31, 即可直接调用 EthernetManager 相关, 设置静态等方法可以通过反射调用设置。 以下是核心设置静态和动态参数工具类,…...

电脑报错提示xinput1_3.dll缺失怎么办?xinput1_3.dll丢失的简单恢复方案
今天,我将为大家分享一个与我们日常工作息息相关的话题——xinput1_3.dll丢失的4种解决方法。在我们的日常工作和生活中,电脑出现问题是常有的事,而xinput1_3.dll丢失则是其中较为常见的一种问题。那么,什么是xinput1_3.dll?它为…...

unity 之参数类型之引用类型
文章目录 引用类型引用类型与值类型的差异 引用类型 在Unity中,引用类型是指那些在内存中存储对象引用的数据类型。以下是在Unity中常见的引用类型的介绍: 节点(GameObject): 在Unity中,游戏对象ÿ…...

SpringBoot自定义工具类—基于定时器完成文件清理功能
直接复制粘贴既可!! import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; import java.io.File; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.ZoneOff…...

安卓设置混淆后,gson报错解决方法
一,设置开启混淆release {minifyEnabled truezipAlignEnabled trueshrinkResources trueproguardFiles getDefaultProguardFile(proguard-android-optimize.txt), proguard-rules.pro } 二,混淆的文件中,对gson相关类不进行混淆,否…...

WPF实战项目十四(API篇):登录注册接口
1、新建UserDto.cs public class UserDto : BaseDto{private string userName;/// <summary>/// 用户名/// </summary>public string UserName{get { return userName; }set { userName value;OnPropertyChanged(); }}private string account;/// <summary>…...

10个免费PPT下载资源网站分享
PPT超级市场https://pptsupermarket.com/ PPT超级市场是一个完全免费的PPT模板下载网站,不需要注册登录,点击下载就能直接使用。 叮当设计https://www.dingdangsheji.com/ 叮当设计是一个完全免费的PPT模板下载网站,每一套PPT的质量都很高。除…...

SpringCloud入门——微服务调用的方式 RestTemplate的使用 使用nacos的服务名初步(Ribbon负载均衡)
目录 引出微服务之间的调用几种调用方法spring提供的组件 RestTemplate的使用导入依赖生产者模块单个配置的情况多个配置的情况没加.yaml的报错【报错】两个同名配置【细节】 完整代码config配置主启动类controller层 消费者模块进行配置restTemplate配置类controller层 使用na…...

Python基础篇(16):python中__new__方法
一、__new__方法的定义 __new__() 方法是一种负责创建 类实例 的 静态方法 二、__new__方法的作用 在内存中为对象分配空间返回对象的引用 三、__new__方法的使用 创建对象时自动调用__new__方法,并且是在__init__初始化方法之前被调用Python解释器获得对象的引…...

linux并发服务器 —— 文件IO相关函数(三)
文件IO 以内存为主体,看待输入输出; 标准C库IO函数带有缓冲区,效率较高; 虚拟地址空间 虚拟地址空间是不存在的,一个应用程序运行期间对应一个虚拟地址空间; 虚拟地址空间的大小由CPU决定,位…...