• [问题求助] cse配置中心里的【应用级配置】和【微服务配置】有什么区别?
    1、什么时候使用应用级配置和微服务配置?2、自定义配置如何配置及使用?
  • [问题求助] 如何从配置中心配置项数据-------cse配置中心【本地】
    把本地【yml】配置文件中的配置属性迁移到【CSE】配置中心,如何动态获取配置项的数据。
  • [干货汇总] 零代码修改,教你Spring Cloud应用轻松接入CSE
    【摘要】 Sermant Agent是一种基于JavaAgent的无代理服务网格技术。它利用JavaAgent来检测主机应用程序,并具有增强的服务治理功能,以解决海量微服务架构中的服务治理问题。本文介绍了Sermant Agent的接入原理和如何使用Sermant Agent无修改接入CSE。本文分享自华为云社区《Spring Cloud应用零代码修改接入华为云微服务引擎CSE》,作者: 微服务小助手 。一、 Sermant Agent介绍Sermant Agent是一种基于JavaAgent的无代理服务网格技术。它利用JavaAgent来检测主机应用程序,并具有增强的服务治理功能,以解决海量微服务架构中的服务治理问题。Sermant Agent处于快速发展阶段,当前已支持多种服务治理能力,包含流量治理、注册、优雅上下线及动态配置能力。 二、 为何使用Sermant Agent接入代码零侵入,配置很简单相较于SDK方式接入,基于Sermant Agent的接入会更加快捷高效,配置简单,且应用无需做任何代码改造,仅需在服务启动时附带Sermant Agent即可动态接入到CSE。支持多种治理能力Sermant Agent默认集成流量治理能力,当前支持熔断、限流、隔离仓以及重试治理能力,该能力可基于CSE配置中心进行配置与发布。支持多种注册中心Sermant Agent目前支持业内主流的注册中心,已经支持了ServiceComb ServiceCenter、Naocs,Eureka、Zookeeper等正在开发中。支持应用不停机迁移Sermant Agent支持服务的双注册,可根据配置中心下发的服务订阅策略,动态修改当前服务的订阅策略,并基于该能力帮助线上应用在业务不中断的前提下完成服务迁移。不仅如此,Sermant Agent提供优雅上下线能力,在服务重启、上下线时提供保障,在保护服务的同时,规避服务下线时可能存在的流量丢失问题。三、 接入原理当然,在说明原理之前,我们首先需要了解什么是Java Agent。Java Agent是在JDK1.5之后引入的新特性,它支持JVM将字节码文件读入内存之后,JVM使用对应的字节流在Java堆中生成一个Class对象之前,用户可以对其字节码进行修改的能力,JVM使用修改之后的字节码进行Class对象的创建,从而实现Java应用的非代码侵入的业务逻辑修改和替换。Sermant Agent正是基于动态修改字节码的技术,在服务启动时,动态增强原服务的注册逻辑。那Sermant Agent是如何在不修改代码的前提下接入CSE呢?主要流程如下:Sermant Agent接入CSE的时序图包含以下6个步骤:首先服务携带Sermant Agent启动;服务启动时,针对服务执行字节码增强操作(基于Java Agent的字节码增强),主要针对注册与配置两块,在步骤3-5体现;通过字节码增强,动态识别原应用的注册中心;注入启动配置,动态关闭原应用的注册中心自动配置逻辑;随后通过Spring的SpringFactory机制注入基于Spring Cloud实现的注册CSE的自动配置类,由Spring接管;当应用发起注册时,会通过步骤5注入的注册逻辑向CSE发起注册,最终完成接入。四、 简单零代码修改,轻松接入CSE接入场景分为虚机接入和容器接入,大家可以根据自身需求选择合适的接入方式。虚机场景接入CSE虚机部署的应用可通过Sermant Agent接入到CSE,点击查看虚机接入CSE流程。接入流程基于ECS将应用接入CSE流程如下:容器场景接入CSE容器部署的应用可通过Sermant Injector自动挂载Sermant Agent,从而通过Sermant Agent接入到CSE,点击查看容器接入CSE流程。接入流程基于CCE将应用接入CSE流程如下:五、 更多支持版本当前Sermant已支持大部分业内主流版本,相关Spring及注册中心版本如下:开源方式接入除了上述接入方式,还可基于开源方式接入,您可在Sermant开源社区拉取最新代码,并自行打包,启动步骤可参考虚机接入流程。开源项目Sermant:https://github.com/huaweicloud/Sermant
  • [问题求助] SpringCloud快速接入CSE启动报错:MicroserviceConfigLoader转String失败
    各位大佬,我在把springCloud快速接入CSE的时候,pom和配置修改完成,启动服务的时候报错,报错信息如下:org.springframework.core.convert.ConverterNotFoundException: No converter found capable of converting from type [org.apache.servicecomb.config.archaius.sources.MicroserviceConfigLoader] to type [java.lang.String]请问这个是什么导致的?怎么解决?
  • [问题求助] CSE可以管理本地启动的微服务吗?
    CSE可以管理本地启动的微服务吗?本地的服务是不是只需要配置华为云CSE上的注册服务发现地址和配置中心地址就可以管理微服务了?还是说必须要把服务部署后才能用CSE管理呢?
  • [问题求助] 项目基于spring-cloud,注册中心用nacos,服务之间调用用的dubbo,现在项目迁移CSE,dubbo这块怎么配置?
    现在公司项目基于spring-cloud-alibaba,注册中心用的nacos,但服务调用没有用openfeign,用的dubbo调的(也是注册到nacos,没有用zookeeper),如图:现在要迁移到华为云,使用CSE的注册中心和配置中心,这一块倒没有问题,官方有文档,就是不知道迁移过去dubbo这一块的配置应该怎么搞,官网只有个基于纯dubbo项目迁移CSE的方案(https://support.huaweicloud.com/devg-cse/cse_devg_0011.html),按照文档说明引入对应maven依赖,就直接报错:
  • [问题求助] ServiceComb打开Tls开关,如何能支持常规非CSE服务间访问的HTTP请求
    ServiceComb打开Tls开关,如何能支持普通非CSE服务间访问的HTTP请求?打开sslEnabled之后,CSE服务间访问确实是走tls,但是常规http请求也是需要https,可否配置部分url走http的策略?
  • [问题求助] 微服务引擎CSE中配置中心请问下怎么用,翻遍了文档没找到
    先说下我的环境和目的我在s3服务器上搭建了cse环境,下载了下载本地轻量化微服务引擎,搭建了注册中心配置中心,同时下载了demo 的basic中的三个服务注册到注册中心去在30103操作页面配置yaml时就遇到了问题,第一个没理解配置管理怎么用第二个,配置了配置项,但是返回读取的信息还是工程里的yaml配置的信息,并不是从配置中心获取的怎么样才能像spring-cloud-config那样让服务从配置中心读取配置项数据呢?哪位大佬帮忙解决下,谢谢
  • [技术干货] 基于sermant 实现dubbo 接入CSE,并实现流量分发
    1、获取Dubbo demo 并打包镜像1.1、Demo GitHub地址:cid:link_0软件包目录软件包名称说明/demo-registry-dubbo/dubbo-provider/dubbo-provider.jar消费者/demo-registry-dubbo/dubbo-consumer/dubbo-consumer.jar生产者1.2、当前文档使用Codehub 存储代码代码上传codehub 指导链接:cid:link_3 1.3、修改 dubbo-consumer 以及 dubbo-provider 下的 /src/main/resources/application.yaml中的address 为 sc://127.0.0.1:30100 如下所示:server: port: 28020 dubbo: application: name: dubbo-consumer protocol: port: 28820 registry: # 模拟存量dubbo应用注册到nacos的情况,新开发的应用建议配置为 sc://127.0.0.1:30100 # address: nacos://127.0.0.1:8848 address: sc://127.0.0.1:301001.4、当前文档基于华为云 Devcloud 进行编译构建dubbo-provider Dockerfile 文件FROM openjdk:8u181-jdk-alpine WORKDIR /opt/provider COPY target/*.jar /opt/provider/provider.jar ENTRYPOINT ["java","-jar","/opt/provider/provider.jar"]dubbo-consumer Dockerfile 文件FROM openjdk:8u181-jdk-alpine WORKDIR /opt/consumer COPY target/*.jar /opt/consumer/consumer.jar ENTRYPOINT ["java","-jar","/opt/consumer/consumer.jar"]1.5、编译构建指导maven 编译构建指导链接:cid:link_6镜像构建推送到华为云SWR指导链接:cid:link_41.6、修改 dubbo-provider 下/src/main/java/com/huawei/dubbotest/impl/TestInterfaceImpl.java ,修改响应参数,如下所示: /** * 测试接口 * * @return 测试信息 */ @Override public Map test() { Map map = new HashMap<>(); // map.put("provider-dubbo-registry-address", registryConfig.getAddress()); # 修改 map.put map.put("灰度测试", "dubbo-provider:v2.0"); return map; } }1.7、重新打包dubbo-provider v2.0镜像,所有打包好的镜像版本如下dubbo-provider:v1.0dubbo-provider:v2.0dubbo-consumer:v1.02、创建华为云CSE2.1、说明:1、当前仅华为云上海一 Region 支持serment 接入CSE2、VPC 需要与后续创建的 CCE 相同2.2、CSE 创建指南链接:cid:link_72.3、获取CSE注册中心以及配置中心地址3、创建华为云CCE3.1、说明:1、创建Region 华为云上海一2、VPC 需要与 CSE相同3、CCE节点1个 4核8G 服务器即可3.2、CCE创建指南链接:cid:link_54、CCE基于模板安装sermant injection4.1、sermant injection 模板下载链接链接:cid:link_14.2、上传至CCE模板4.3、基于CCE节点安装 kubectl 客户端链接:cid:link_24.4、在已安装 kubectl 的节点上申请Sermant Injector https证书wget -O- https://cse-bucket-cn-east-3.obs.cn-east-3.myhuaweicloud.com/javaagent/certificate.sh | sh4.5、获取K8s 集群证书kubectl config view --raw --minify --flatten -o jsonpath='{.clusters[].cluster.certificate-authority-data}'4.6、使用模板安装 sermant-injection1、CCE 控制台进入集群模板管理点击sermant injection的安装按钮 2、输入实例名称,配制yaml文件并安装,yaml内容如下:agent: image: version: 0.5.1 cse: config: # CSE配置中心地址,输入2.3中获取的地址 endpoints: https://192.168.0.xx:30110,https://192.168.0.xx:30110 registry: # CSE注册中心地址,输入2.3中获取的地址 endpoints: https://192.168.0.xxx:30100,https://192.168.0.xx:30100 image: pullPolicy: IfNotPresent # CCE所在的region,cn-east-3(华东-上海一) region: cn-east-3 injector: image: pullSecrets: default-secret version: 0.5.1 # injector实例数,若CCE集群只有一个节点,则需配置为1 replicas: 2 webhooks: # K8s集群证书,输入4.5中获取到的证书内容 caBundle: xxxxxx==5、部署应用5.1、部署dubbo-consumerapiVersion: apps/v1 kind: Deployment metadata: labels: version: v1 name: consumer spec: selector: matchLabels: app: consumer version: v1 template: metadata: labels: app: consumer version: v1 sermant-injection: enabled spec: containers: - image: '输入 dubbo-consumer v1.0 SWR的镜像地址' name: container-0 imagePullSecrets: - name: default-secret terminationGracePeriodSeconds: 30 dnsPolicy: ClusterFirst replicas: 15.2、部署 dubbo-provider v1.0apiVersion: apps/v1 kind: Deployment metadata: labels: version: v1 name: provider spec: selector: matchLabels: app: provider version: v1 template: metadata: labels: app: provider version: v1 sermant-injection: enabled spec: containers: - image: '输入 dubbo-provider V1.0 SWR的镜像地址' name: container-0 imagePullSecrets: - name: default-secret terminationGracePeriodSeconds: 30 dnsPolicy: ClusterFirst replicas: 15.3、部署 dubbo-provider v2.0apiVersion: apps/v1 kind: Deployment metadata: labels: version: v1 name: provider-v101 spec: selector: matchLabels: app: provider-v101 version: v1 template: metadata: labels: app: provider-v101 version: v1 sermant-injection: enabled spec: containers: - image: '输入 dubbo-provider V2.0 SWR的镜像地址' name: container-0 env: # 指定微服务版本号为 1.0.1 ,不指定时默认为 1.0.0 - name: SERVICE_META_VERSION value: 1.0.1 # 指定微服务所属应用为 default,不指定时默认为default - name: SERVICE_META_APPLICATION value: default imagePullSecrets: - name: default-secret terminationGracePeriodSeconds: 30 dnsPolicy: ClusterFirst replicas: 15.4 为dubbo-consumer 添加service,提供对外访问方式apiVersion: v1 kind: Service metadata: name: '' labels: app: consumer namespace: default spec: selector: app: consumer externalTrafficPolicy: Cluster ports: - name: cce-service-0 targetPort: 28020 nodePort: 0 port: 28020 protocol: TCP type: NodePort6、访问验证6.1、获取访问方式,http://节点ip:30740 6.2、http://节点ip:30740/test 进行服务访问 7、查看微服务的注册情况7.1、dubbo-consumer 注册情况 7.2、dubbo-provider v1.0 注册情况 7.3、dubbo-provider v2.0 注册情况 8、添加路由规则实现,流量控制8.1、在CSE控制台配置管理点击新建配制配置项:servicecomb.routeRule.{微服务名称}配置范围:应用级配置应用:按应用和环境实际情况填写,默认为:default <空>配置格式: yaml配置内容如下:--- - precedence: 2 route: - weight: 10 tags: version: 1.0.0 - weight: 90 tags: version: 1.0.18.2、通过脚本访问服务,并统计 provider v1.0 请求次数占比 10% , provider v2.0 请求次数占比 90%;与设置的规则相匹配8.3、python脚本内容import requests import threading import time list= [] class postrequests(): def __init__(self): # 需要修改连接 self.url = 'http://{服务器ip}:{端口}/test' # 请求链接 # self.data = {'phone': '176*****286', 'code': '12***6'} # 传递参数 # self.headers = {'content-type': 'application/json'} # 请求头 # self.data = json.dumps(self.data) def post(self): try: # r = requests.post(self.url, self.data, headers=self.headers) r = requests.get(self.url) # print(r.text) list.append(r.text) except Exception as e: print(e) def kquan_bf(): login = postrequests() return login.post() try: i = 0 # 开启线程数目 tasks_number = 100 print('测试启动') list = [] while i < tasks_number: t = threading.Thread(target=kquan_bf) t.start() i += 1 time.sleep(10) print(list) print("请求次数:") print("灰度测试"+" : "+str(list.count("{灰度测试=dubbo-provider:v2.0}"))) print("sc://localhost:30100"+" : "+str(list.count("{provider-dubbo-registry-address=sc://localhost:30100}"))) except Exception as e: print(e) # 请求结果
  • [问题求助] CSE有没有方式能够指定ip和port发起调用
    如题,CSE有没有方式能够指定ip和port发起调用
  • [技术交流] SpringCloud项目接入华为云微服务引擎CSE
    ### 一、SpringCloud项目架构介绍 #### 1.项目地址: [https://gitee.com/caichunfu/dtse-practice-microservice](https://gitee.com/caichunfu/dtse-practice-microservice) #### 2.项目技术栈如下: 1. 注册中心:Eureka 2. 网关:zuul 3. 声明式调用:feign 4. 存储:OBS、RDS for MySql ![](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20222/18/1645173154462340346.png) #### 3.项目结构: 1. dtse-commons:项目的公共工具类 2. dtse-eureka-server:eureka注册中心集群 3. dtse-feign-client:feign调用客户端 4. dtse-obs-storage:服务端,完成对obs的操作,包括上传和删除obs对象 5. dtse-system:消费端,实现用户登录、查询用户头像、更新用户头像(调用服务端请求) 6. dtse-zuul-getway:项目网关 ### 二、SpringCloud Huawei改造方案 #### 1.替换技术栈对比 | SpringCloud | SpringCloud-Huawei | | ------------------ | ------------------------------------------------------------ | | Eureka注册中心 | [华为云CSE微服务引擎](https://support.huaweicloud.com/devg-cse/cse_devg_0010.html) | | zuul网关 | SpringCloud Huawei Getway | | SpringCloud config | [CSE Config](https://support.huaweicloud.com/devg-cse/cse_devg_0022.html) | #### 2.SpringCloud Huawei技术文档 [https://github.com/huaweicloud/spring-cloud-huawei](https://github.com/huaweicloud/spring-cloud-huawei) #### 3.SpringCloud Huawei基础Demo [https://github.com/huaweicloud/spring-cloud-huawei-samples/tree/master/basic](https://github.com/huaweicloud/spring-cloud-huawei-samples/tree/master/basic) #### 4.SpringCloud Huawei版本对照 ![](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20222/18/1645174723327212698.png) #### 5.改造前设置 1. 下载本地CSE,下载地址:[https://support.huaweicloud.com/devg-cse/cse_devg_0036.html](https://support.huaweicloud.com/devg-cse/cse_devg_0036.html) 2. 将maven镜像改为华为镜像仓库: ``` <mirror> <id>huaweicloud</id> <mirrorOf>*</mirrorOf> <url>https://repo.huaweicloud.com/repository/maven/</url> </mirror> ``` 3. 项目版本选定 - SpringBoot:2.3.7.RELEASE - SpringCloud:Hoxton.SR9 - SpringCloud Huawei:1.8.0-Hoxton #### 6.改造方案 1. 移除微服务项目里所有的eureka依赖,删掉application.yml里的eureka的配置 ``` <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId> </dependency> ``` 2. 导入SpringCloud Huawei依赖 - 父工程里导入 ```xml <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>${spring-cloud.version}</version> <type>pom</type> <scope>import</scope> </dependency> ``` - 子工程里导入 ```xml <dependency> <groupId>com.huaweicloud</groupId> <artifactId>spring-cloud-starter-huawei-service-engine</artifactId> </dependency> ``` 3. 添加bootstrap.yaml配置文件 ```yaml spring: application: name: #微服务名 cloud: servicecomb: discovery: enabled: true address: http://127.0.0.1:30100 appName: basic-application serviceName: ${spring.application.name} version: 0.0.1 healthCheckInterval: 30 config: serverAddr: http://127.0.0.1:30110 serverType: kie ``` 4. 解决启动中的报错 4.1. 需要编写IClientConfig配置类: ![](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20222/18/1645176166364496834.png) ![](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20222/18/1645176147975776732.png) 4.2. 配置类添加 ![](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20222/18/1645176207306600820.png) ![](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20222/18/1645176216784964848.png) 4.3. 微服务里无数据库配置: ![](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20222/18/1645176276185922690.png) 需要在启动类上加`@SpringBootApplication(exclude={DataSourceAutoConfiguration.class})` 4.4. feign调用报错 ![](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20222/18/1645176345773477730.png) SpringCloud Huawei当前版本对负载均衡支持不够友好,openfeign自带负载均衡,建议使用RestTemplate *以下解决方法来自本站的帖子[SpringCloud项目接入华为云微服务引擎CSE(一)](https://bbs.huaweicloud.com/forum/thread-178657-1-1.html)* 4.5. 修改openfeign调用为RestTemplate - 在dtse-system--usercontroller--UpdateIconImage路径对应的方法里注释掉openfeign调用代码 - 添加RestTemplate方式调用的代码 ```java //请求url String url = "http://xxxx:xxxx/xx/x"; ​ //构造请求头 HttpHeaders httpHeaders = new HttpHeaders(); HttpHeaders headers = httpHeaders; headers.setContentType(MediaType.MULTIPART_FORM_DATA); ​ //FileSystemResource将文件变成流以发送 File file = MultipartFileToFile.multipartFileToFile(multipartFile); FileSystemResource fileSystemResource = new FileSystemResource(file); ​ //构造请求体,使用LinkedMultiValueMap MultiValueMap<String, Object> resultMap = new LinkedMultiValueMap<>(); resultMap.add("file", fileSystemResource); resultMap.add("obsParamsJson", obsParamsJson); ​ //HttpEntity封装整个请求报文 HttpEntity<MultiValueMap<String, Object>> httpEntity = new HttpEntity<>(resultMap, headers); ​ //postForObject发送请求体 String objURL = restTemplate.postForObject(url, httpEntity, String.class); ``` **MultipartFile转File:** ```java import org.springframework.web.multipart.MultipartFile; import java.io.File; import java.io.FileOutputStream; import java.io.InputStream; import java.io.OutputStream; ​ public class MultipartFileToFile { /** * MultipartFile 转 File * * @param file * @throws Exception */ public static File multipartFileToFile(MultipartFile file) throws Exception { File toFile = null; if (file.equals("") || file.getSize() <= 0) { file = null; } else { InputStream ins = null; ins = file.getInputStream(); toFile = new File(file.getOriginalFilename()); inputStreamToFile(ins, toFile); ins.close(); } return toFile; } //获取流文件 private static void inputStreamToFile(InputStream ins, File file) { try { OutputStream os = new FileOutputStream(file); int bytesRead = 0; byte[] buffer = new byte[8192]; while ((bytesRead = ins.read(buffer, 0, 8192)) != -1) { os.write(buffer, 0, bytesRead); } os.close(); ins.close(); } catch (Exception e) { e.printStackTrace(); } } /** * 删除本地临时文件 * @param file */ public static void delteTempFile(File file) { if (file != null) { File del = new File(file.toURI()); del.delete(); } } } ``` 4.6 网关改造 - 删除原项目zuul的依赖,添加springcloudgateway的依赖和springcloudhuawei提供的网关依赖 ```xml <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-gateway</artifactId> </dependency> <dependency> <groupId>com.huaweicloud</groupId> <artifactId>spring-cloud-starter-huawei-service-engine-gateway</artifactId> </dependency> ``` - 添加网关配置文件(注意uri不要用lb地址,当前版本涉及负载均衡的均有问题,暂时用固定地址) ```yaml spring: main: allow-bean-definition-overriding: true cloud: gateway: # 路由(routes:路由,它由唯一标识(ID)、目标服务地址(uri)、一组断言(predicates)和一组过滤器组成(filters)。filters 不是必需参数。) routes: #路由标识(id:标识,具有唯一性) - id: dtse-system-route # 目标服务地址(uri:地址,请求转发后的地址) #uri: lb://dtse-system #不要用lb地址 uri: http://localhost:9090 filters: args: # 路由条件(predicates:断言,匹配 HTTP 请求内容) predicates: - Path=/** urifiler: login-uri: /login ``` - 定义全局过滤器实现鉴权 ```java @Component @Slf4j public class RouteConfiguration implements GlobalFilter, Ordered { ​ @Autowired JwtUtil jwtUtil; @Autowired URIFilter uriFilter; ​ @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { ​ ServerHttpRequest request = exchange.getRequest(); RequestPath path = request.getPath(); ​ // 2、登陆请求放行 if(path.value().contains(uriFilter.getLoginuri().get(0))){ System.out.println("登陆请求路经:request.getPath() = " + path.value()); log.info("登录"); return chain.filter(exchange); } //3、非登陆请求用户权限校验 String authorization = request.getHeaders().getFirst("Authorization"); if (!StringUtils.isEmpty((authorization))) { System.out.println("非登陆请求路径:request.getPath() = " + path.value()); //2、获取请求头中Token信息 String token = authorization.replace("Bearer", ""); ​ //3、Token校验 Claims claims = jwtUtil.parseToken(token) ; ​ //4、获取用户id,并将用户id传送到后端 if (claims == null) { try { throw new Exception(String.valueOf(ResultCode.UNAUTHENTICATED)); } catch (Exception e) { e.printStackTrace(); } return null; } String id = claims.getId(); ​ //5、添加用户请求头 request.mutate().header("userId",id).build(); return chain.filter(exchange); } ​ return chain.filter(exchange); } ​ @Override public int getOrder() { return 0; } } ``` - urifiler配置类 ```java @ConfigurationProperties(prefix = "urifiler", ignoreUnknownFields = false) @Data @Component public class URIFilter { private List<String> loginuri; } ``` 4.7 配置中心 在浏览器输入http://127.0.0.1:30103/,进入cse可视化界面,选择配置列表,创建配置项 ![](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20222/21/1645427195901258209.png)
  • [技术交流] SpringCloud项目接入华为云微服务引擎CSE(二)
    目录1.    业务架构说明2.    开发环境3.    本地CSE开发环境搭建    3.1.    下载本地CSE    3.2.    解压,双击cse.exe    3.3.    登录CSE控制台4.    接入前准备    4.1.    下载实验工程源码,使用IDEA打开    4.2.    IDE 配置    4.3.    Maven配置5.    服务端CSE接入    5.1.    主pom修改    5.2.    dtse-feign-client接入    5.3.    dtse-obs-storage接入    5.4.    dtse_system接入    5.5.    dtse-zuuL-gateway网关接入6.    前端服务接入7.    其他接入中问题记录    1. 业务架构说明    项目Gitee地址     后端   https://gitee.com/caichunfu/dtse-practice-microservice     前端   https://gitee.com/HuaweiCloudDeveloper/dtse-practice-frontEnd/tree/devCSE改造前:    • 微服务包含4个微服务模块:zuul-gateway模块、Eureka注册中心、dtse-system模块、obs-storage模块;其中dtse-system模块、obs-storage模块是业务模块。    • 用户发送请求,微服务网关(zuul-gateway) 过滤器根据请求URI,路由和负载均衡请求到不同服务;同时利用JWT进行token校验请求的合法性。    • Eureka注册中心管理zuul-gateway、dtse-system、obs-storage微服务状态;    • dtse-system与obs-storage之间通过feign进行内部接口调用改造技术路径    • 引入使用spring-cloud-huawei    • 使用华为云CSE服务替换Eureka注册中心的功能    • 使用Spring Cloud Gateway替换zuul网关基线版本选择    查看 spring-cloud-huawei官网地址:    https://github.com/huaweicloud/spring-cloud-huawei     通过实践master分支与openFeign存在兼容问题,所以本次实践以Hoxton为基线版本,Hoxten与openFeign不存在兼容性问题    由于Spring Cloud Huawei与zuul调试中发现有兼容问题,所以将网关替换成Spring Cloud Gateway2. 开发环境JDKOpenjdk 1.8.0_312Maven3.6.3IDEA2021.2.2CSELocal-CSE-2.1.3-windows-amd64.zipspring-boot2.3.5.RELEASEspring-cloudHoxton.SR9spring-cloud-huawei1.8.0-Hoxton3. 本地CSE开发环境搭建3.1. 下载本地CSE    https://cse-bucket.obs.cn-north-1.myhuaweicloud.com/LocalCSE/Local-CSE-2.1.3-windows-amd64.zip 3.2. 解压,双击cse.exe3.3. 登录CSE控制台    http://127.0.0.1:30103 4. 接入前准备4.1. 下载实验工程源码,使用IDEA打开    源码地址 https://gitee.com/caichunfu/dtse-practice-microservice 4.2. IDE 配置4.3. Maven配置    使用华为云Maven5. 服务端CSE接入改造5.1. 主pom改造5.1.1. 主pom引入依赖5.1.2. 使用CSE做为注册中心,删除相关模块和依赖    a、删除eureka-server    b、引入华为spring cloud` <properties> <java.version>1.8</java.version> <spring-boot.version>2.3.5.RELEASE</spring-boot.version> <spring-cloud.version>Hoxton.SR9</spring-cloud.version> <spring-cloud-huawei.version>1.8.0-Hoxton</spring-cloud-huawei.version> </properties>`<!-- configure user spring cloud / spring boot versions --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>${spring-boot.version}</version> <type>pom</type> <scope>import</scope> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>${spring-cloud.version}</version> <type>pom</type> <scope>import</scope> </dependency> <!-- configure spring cloud huawei version --> <dependency> <groupId>com.huaweicloud</groupId> <artifactId>spring-cloud-huawei-bom</artifactId> <version>${spring-cloud-huawei.version}</version> <type>pom</type> <scope>import</scope> </dependency>5.2. dtse-feign-client接入5.2.1. 引入openfeign版本<dependency> <groupId>io.github.openfeign.form</groupId> <artifactId>feign-form-spring</artifactId> <version>3.8.0</version> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-openfeign-core</artifactId> <version>3.0.3</version> </dependency>5.3. dtse-obs-storage接入5.3.1. Pom文件处理5.3.1.1. 删除zuul依赖    删除spring-cloud-starter-netflix-zuul,增加spring-cloud-starter-netflix-ribbon <!--wmh add--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-ribbon</artifactId> <version>2.2.0.RELEASE</version> <scope>compile</scope> <exclusions> <exclusion> <artifactId>ribbon-transport</artifactId> <groupId>com.netflix.ribbon</groupId> </exclusion> <exclusion> <artifactId>rxnetty</artifactId> <groupId>io.reactivex</groupId> </exclusion> </exclusions> <optional>true</optional> </dependency> <!-- wmh delete <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-zuul</artifactId> </dependency> -->5.3.2. 引入CSE配置5.3.3. 处理com.netflix.client.config.IClientConfig‘ that could not be found问题    出现这种问题是因为启动类找不到(扫描)其他类的路径,处理方法有多种,我这边使用的是方法二    方法一:把启动类放在其他类文件包的同一级,而不要放在上一级    方法二:在启动类的标签中加入启动扫描的路径如下:    方法三: new个IClientConfig类,不过需要初始化,不然会出现空指针5.3.3.1. 方法二指定扫描路径:    SpringBootApplication指定扫描路径@SpringBootApplication(scanBasePackages = {"com.huaweicloud.controller","com.huaweicloud.service","com.huaweicloud.commons","com.huaweicloud.persistent"}) @EnableFeignClients @EnableDiscoveryClient public class OBSStorageMain { public static void main(String[] args) { SpringApplication.run(OBSStorageMain.class, args); } }5.3.3.2. 方法三增加config类:    IClientConfig 类,重点来了,就是这个类,如果不自己定义(openFeign 是可以自定义这个类的,然后自己初始化),那么就千万不要自己去创建一个 bean 出来,然后自己加上注解定义成配置类如下:@Configuration public class IClientConfig { @Bean public DefaultClientConfigImpl iClientConfig(){ return new DefaultClientConfigImpl(); } }    这玩意千万不要在程序里自己创建出来,可能很多初学者不是很懂,一开始有配置了这个,结果又只是单纯的 return 了一个没有任何属性的 DefaultClientConfigImpl 对象,然后 openFeign 就会使用你创建的这个对象,结果去初始化的时候,就会在源码里面报空指针异常,把这玩意去掉,基本就可以了,如果要自己定义,那记得把里面该有的属性都要初始化值。5.4. Dtse_system接入5.4.1. Pom文件处理    删除eureka client,引入华为service engine <!-- <dependency>--> <!-- <groupId>org.springframework.cloud</groupId>--> <!-- <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>--> <!-- </dependency>--> <dependency> <groupId>com.huaweicloud</groupId> <artifactId>spring-cloud-starter-huawei-service-engine</artifactId> </dependency>删除netflix-hystrix <!-- <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-hystrix</artifactId> </dependency>-->5.4.2. 引入CSE配置5.4.3. 处理com.netflix.client.config.IClientConfig‘ that could not be found问题package com.huaweicloud; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.openfeign.EnableFeignClients; @SpringBootApplication(scanBasePackages = {"com.huaweicloud.controller","com.huaweicloud.commons","com.huaweicloud.service","com.huaweicloud.persistent"}) @EnableFeignClients //开启feign客户端调用支持 public class SystemMain { public static void main(String[] args) { SpringApplication.run(SystemMain.class, args); } }5.5. Dtse-zuuL-gateway网关接入    使用spring cloud huawei与zuul有兼容性问题,所以切换到Spring Cloud Gateway5.5.1. Pom文件处理    spring-boot-starter-web排除spring-webmvc包,删除spring-cloud-starter-netflix-zuul包 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <exclusions> <exclusion> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> </exclusion> </exclusions> </dependency>    删除eureka-client包 <!-- <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency>-->    引入spring-cloud-starter-gateway和huawei-service-engine-gateway <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-gateway</artifactId> </dependency> <dependency> <groupId>com.huaweicloud</groupId> <artifactId>spring-cloud-starter-huawei-service-engine-gateway</artifactId> </dependency>5.5.2. 引入CSE配置    修改网关配置5.5.3. 修改网关全局过滤器package com.huaweicloud.filter; import com.huaweicloud.commons.outhUtils.JwtUtil; import com.huaweicloud.commons.response.ResultCode; import com.huaweicloud.config.URIFilter; import io.jsonwebtoken.Claims; import org.apache.servicecomb.foundation.common.utils.JsonUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cloud.gateway.filter.GatewayFilterChain; import org.springframework.cloud.gateway.filter.GlobalFilter; import org.springframework.core.Ordered; import org.springframework.core.annotation.Order; import org.springframework.http.server.RequestPath; import org.springframework.http.server.reactive.ServerHttpRequest; import org.springframework.stereotype.Component; import org.springframework.util.StringUtils; import org.springframework.web.server.ServerWebExchange; import reactor.core.publisher.Mono; import java.lang.annotation.Annotation; @Component public class RouteConfiguration implements GlobalFilter, Ordered { @Autowired JwtUtil jwtUtil; @Autowired URIFilter uriFilter; private String writeJson(Object o) { try { return JsonUtils.writeValueAsString(o); } catch (Exception ee) { ee.printStackTrace(); } return null; } @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { System.out.println("access filter......"); ServerHttpRequest request = exchange.getRequest(); RequestPath path = request.getPath(); System.out.println("收到请求路经:request.getPath() = " + path.value()); // 2、登陆请求放行 if(path.value().contains(uriFilter.getLoginuri().get(0))){ System.out.println("登陆请求路经:request.getPath() = " + path.value()); return chain.filter(exchange); } //3、非登陆请求用户权限校验 String authorization = request.getHeaders().getFirst("Authorization"); if (!StringUtils.isEmpty((authorization))) { System.out.println("非登陆请求路径:request.getPath() = " + path.value()); //2、获取请求头中Token信息 String token = authorization.replace("Bearer", ""); //3、Token校验 Claims claims = jwtUtil.parseToken(token) ; //4、获取用户id,并将用户id传送到后端 if (claims == null) { try { throw new Exception(String.valueOf(ResultCode.UNAUTHENTICATED)); } catch (Exception e) { e.printStackTrace(); } return null; } String id = claims.getId(); //5、添加用户请求头 request.mutate().header("userId",id).build(); return chain.filter(exchange); } return chain.filter(exchange); } @Override public int getOrder() { return 0; } }5.5.4. 处理com.netflix.client.config.IClientConfig‘ that could not be found问题package com.huaweicloud; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; @SpringBootApplication(exclude = {DataSourceAutoConfiguration.class},scanBasePackages = {"com.huaweicloud.config","com.huaweicloud.filter","com.huaweicloud.commons"}) @EnableDiscoveryClient public class SpringCloudGatewayMain { public static void main(String[] args) throws Exception { SpringApplication.run(SpringCloudGatewayMain.class, args); } }6. 前端服务接入    修改vue.config.js,配置服务网关服务的端口    修改login.Vue,通过网关经过systemmain统一接入,所以修改登录url    修改图片上传接口,和获取用户信息接口7. 其他接入中问题记录7.1. 方便openFeign调试,openFeign调试,增加Feign日志类config 增加类FeignConfigurationpackage com.huaweicloud.config; import feign.Logger; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class FeignConfiguration { /** * 日志级别 * * @return */ @Bean Logger.Level feignLoggerLevel() { return Logger.Level.FULL; } }7.2. Idea 编译报错:Ambiguous method call. Both...    IDEA Settings... > Plugins > 搜索已安装的插件Hrisey Plugins > 禁用该插件 7.3. gateway报错org. springframework.cloud.gateway.config.GatewayAutoConfiguration required a bean of type 'org.springframework.http.codec.ServerCodec Configurer' that could not be found      spring-cloud-starter-gateway依赖与mvc是不兼容的,如果要引用spring-boot-starter-web需要把mvc排除 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <exclusions> <exclusion> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> </exclusion> </exclusions> </dependency>7.4. OpenFeign调用报错com.netflix.client.ClientException: Load balancer does not have available server for client: DTSE-OBS-STORAGE    yml 文件里面的服务名,要和 @FeignClient(value = "xxx") 里面的 xxx 一样,切记别弄错,大小写也要一致
  • [技术交流] SpringCloud项目接入华为云微服务引擎CSE(一)
    1.项目Gitee地址https://gitee.com/caichunfu/dtse-practice-microservice2.运行环境JDK1.8Maven3.6.3本地CSE引擎下载地址:https://support.huaweicloud.com/devg-cse/cse_devg_0036.html3.注意事项踩过的一些坑:3.1依赖导入报错需要把Maven的中央仓库地址改为华为中央仓库地址,修改setting.xml文件      <mirror>          <id>huaweicloud</id>          <mirrorOf>*,!HuaweiCloudSDK</mirrorOf>          <url>https://repo.huaweicloud.com/repository/maven/</url>     </mirror>3.2版本问题官网地址:https://github.com/huaweicloud/spring-cloud-huawei1)使用Hoxton分支,项目启动时ribbon的启动类会报错,建议使用master分支com.huaweicloud.servicecomb.discovery.ribbon.ServiceCombRibbonClientConfiguration required a bean of type 'com.netflix.client.config.IClientConfig' that could not be found.2)master分支1.8.0-2020.0.x与网关存在兼容性问题,建议使用1.6.1-2020.0.x版本3)master分支需要使用 springcloud 2020.x 的版本,这个版本移除了Netflix相关的组件,所以需要对组件进行替换3.3本次测试使用的版本   <properties>       <spring-boot.version>2.5.3</spring-boot.version>       <spring-cloud.version>2020.0.4</spring-cloud.version>       <spring-cloud-huawei.version>1.6.1-2020.0.x</spring-cloud-huawei.version>       <servicecomb.version>2.5.0</servicecomb.version>       <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>   </properties>4.引入依赖4.1父工程引入 <dependencyManagement>      <!-- configure spring cloud huawei version -->      <dependency>        <groupId>com.huaweicloud</groupId>        <artifactId>spring-cloud-huawei-bom</artifactId>        <version>${spring-cloud-huawei.version}</version>        <type>pom</type>        <scope>import</scope>      </dependency>    </dependencies>  </dependencyManagement>4.2子工程引入,并删除eureka相关依赖<dependency>  <groupId>com.huaweicloud</groupId>  <artifactId>spring-cloud-starter-huawei-service-engine</artifactId></dependency>5.创建bootstrap.yml文件spring: application:   name: #微服务名 cloud:   servicecomb:     discovery:       enabled: true       address: http://127.0.0.1:30100       appName: #应用名       serviceName: ${spring.application.name}       version: 0.0.1       healthCheckInterval: 30     config:       serverAddr: http://127.0.0.1:30110       serverType: kie6.启动类添加注解@EnableDiscoveryClient启动本地微服引擎,访问http://127.0.0.1:30103/进入微服务引擎管理界面,查看服务是否注册成功7.启动前遇到的问题7.1报错信息:could not be registered. A bean with that name has already been defined in URL ​Action:​Consider renaming one of the beans or enabling overriding by setting spring.main.allow-bean-definition-overriding=true​无法注册。URL中已经定义了一个具有该名称的bean​考虑重命名一个bean,或者通过设置Spring实现重写。主要的允许bean定义覆盖=true解决方案:yml配置文件添加配置spring: main:   allow-bean-definition-overriding: true7.2报错信息:Action:​Correct the classpath of your application so that it contains a single, compatible version of io.micrometer.core.instrument.distribution.DistributionStatisticConfig$Builder解决方案:pom.xml里面的依赖包有重复,需要将重复的依赖包删除7.3报错信息:此问题只会在使用Honxton版本时出现,建议使用master分支1.6.1-2020.0.x版本Parameter 0 of method ribbonServerList in com.huaweicloud.servicecomb.discovery.ribbon.ServiceCombRibbonClientConfiguration required a bean of type 'com.netflix.client.config.IClientConfig' that could not be found.​Action:​Consider defining a bean of type 'com.netflix.client.config.IClientConfig' in your configuration.解决方案:IClientConfig 类,这个类定义时,不能直接 return 一个没有任何属性的 DefaultClientConfigImpl 对象, openFeign 会在源码里面使用这个对象,报空指针异常,如果要自己定义,需要初始化里面该有的属性@Configurationpublic class IClientConfig {   @Bean   public DefaultClientConfigImpl iClientConfig(){           //网上很多的错误写法       //return new DefaultClientConfigImp();               //加上getClientConfigWithDefaultValues初始化参数       return DefaultClientConfigImpl.getClientConfigWithDefaultValues();   }}8.Feign远程调用使用SpringCloudHuawei做远程调用时会报错,可能兼容性存在问题为了验证问题还原了SpringCloud项目,openfeign调用不会报错报错信息:org.apache.servicecomb.service.center.client.exception.OperationException: get service instances list fails, statusCode = 400; message = Bad Request; content = {"errorCode":"400012","errorMessage":"Micro-service does not exist","detail":"Consumer[30b75156753bc55385a7ae74d0611c77fc5f7522][development/dtse-practice-microservice/dtse-system/0.0.1] find provider[development/dtse-practice-microservice/default/0+] failed, provider does not exist"}​Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is java.lang.RuntimeException: com.netflix.client.ClientException: Load balancer does not have available server for client: default解决---暂未解决:已对接后端技术专家,暂未解决,解决后会更新进度9.改为RestTemplate方式调用前端参数为MultipartFile和JSON,请求类型为POST    @PostMapping(value = "/upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)    public String upLoadOneFile(@RequestPart("file") MultipartFile file, @RequestParam("obsParamsJson") String obsParamsJson) throws IOException {                OBSStorageParams obsParams = JSON.parseObject(obsParamsJson, OBSStorageParams.class);​        String objURL = obsService.uploadOneFile(file.getInputStream(), obsParams);        return objURL;   }RestTemplate调用代码        //请求url        String url = "http://xxxx:xxxx/xx/x";​        //构造请求头        HttpHeaders httpHeaders = new HttpHeaders();        HttpHeaders headers = httpHeaders;        headers.setContentType(MediaType.MULTIPART_FORM_DATA);​        //FileSystemResource将文件变成流以发送        File file = MultipartFileToFile.multipartFileToFile(multipartFile);        FileSystemResource fileSystemResource = new FileSystemResource(file);​        //构造请求体,使用LinkedMultiValueMap        MultiValueMap<String, Object> resultMap = new LinkedMultiValueMap<>();        resultMap.add("file", fileSystemResource);        resultMap.add("obsParamsJson", obsParamsJson);​        //HttpEntity封装整个请求报文        HttpEntity<MultiValueMap<String, Object>> httpEntity = new HttpEntity<>(resultMap, headers);​        //postForObject发送请求体        String objURL = restTemplate.postForObject(url, httpEntity, String.class);MultipartFile转File import org.springframework.web.multipart.MultipartFile; import java.io.File;import java.io.FileOutputStream;import java.io.InputStream;import java.io.OutputStream;​public class MultipartFileToFile {    /**     * MultipartFile 转 File     *     * @param file     * @throws Exception     */    public static File multipartFileToFile(MultipartFile file) throws Exception {        File toFile = null;        if (file.equals("") || file.getSize() <= 0) {            file = null;       } else {            InputStream ins = null;            ins = file.getInputStream();            toFile = new File(file.getOriginalFilename());            inputStreamToFile(ins, toFile);            ins.close();       }        return toFile;   }    //获取流文件    private static void inputStreamToFile(InputStream ins, File file) {        try {            OutputStream os = new FileOutputStream(file);            int bytesRead = 0;            byte[] buffer = new byte[8192];            while ((bytesRead = ins.read(buffer, 0, 8192)) != -1) {                os.write(buffer, 0, bytesRead);           }            os.close();            ins.close();       } catch (Exception e) {            e.printStackTrace();       }   }    /**     * 删除本地临时文件     * @param file     */    public static void delteTempFile(File file) {    if (file != null) {        File del = new File(file.toURI());        del.delete();   }}}10.网关改造官网的说明:Spring Cloud Huawei Hoxton分支只提供Spring Cloud Gateway基于Ribbon的负载均衡,及其配套的基于流量治理和灰度发布功能。 Spring Cloud Huawei master(2020.0.x版本)分支只提供Spring Cloud Gateway基于Spring Cloud LoadBalance的负载均衡, 及其配套的基于流量治理和灰度发布功能。建议Spring Cloud Gateway升级到2020.0.x版本。由于原项目使用的网关为Zuul,需要改为Spring Cloud Gateway10.1删除原项目zuul的依赖,添加springcloudgateway的依赖和springcloudhuawei提供的网关依赖<dependency>   <groupId>org.springframework.cloud</groupId>   <artifactId>spring-cloud-starter-gateway</artifactId></dependency><dependency>   <groupId>com.huaweicloud</groupId>   <artifactId>spring-cloud-starter-huawei-service-engine-gateway</artifactId></dependency>10.2添加网关配置文件spring: main:   allow-bean-definition-overriding: true cloud:   gateway:    # 路由(routes:路由,它由唯一标识(ID)、目标服务地址(uri)、一组断言(predicates)和一组过滤器组成(filters)。filters 不是必需参数。)     routes:     #路由标识(id:标识,具有唯一性)       - id: dtse-system-route        # 目标服务地址(uri:地址,请求转发后的地址)         uri: lb://dtse-system         filters:             args: # 路由条件(predicates:断言,匹配 HTTP 请求内容)         predicates:           - Path=/**urifiler: login-uri: /login10.3定义全局过滤器实现鉴权package com.huaweicloud.filter;​import com.huaweicloud.commons.outhUtils.JwtUtil;import com.huaweicloud.commons.response.ResultCode;import com.huaweicloud.config.URIFilter;import io.jsonwebtoken.Claims;import lombok.extern.slf4j.Slf4j;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.cloud.gateway.filter.GatewayFilterChain;import org.springframework.cloud.gateway.filter.GlobalFilter;import org.springframework.core.Ordered;import org.springframework.http.server.RequestPath;import org.springframework.http.server.reactive.ServerHttpRequest;import org.springframework.stereotype.Component;import org.springframework.util.StringUtils;import org.springframework.web.server.ServerWebExchange;import reactor.core.publisher.Mono;​@Component@Slf4jpublic class RouteConfiguration implements GlobalFilter, Ordered {​    @Autowired    JwtUtil jwtUtil;    @Autowired    URIFilter uriFilter;​    @Override    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {​        ServerHttpRequest request = exchange.getRequest();        RequestPath path = request.getPath();​        // 2、登陆请求放行        if(path.value().contains(uriFilter.getLoginuri().get(0))){            System.out.println("登陆请求路经:request.getPath() = " + path.value());            log.info("登录");            return chain.filter(exchange);       }        //3、非登陆请求用户权限校验        String authorization = request.getHeaders().getFirst("Authorization");        if (!StringUtils.isEmpty((authorization))) {            System.out.println("非登陆请求路径:request.getPath() = " + path.value());            //2、获取请求头中Token信息            String token = authorization.replace("Bearer", "");​            //3、Token校验            Claims claims = jwtUtil.parseToken(token) ;​            //4、获取用户id,并将用户id传送到后端            if (claims == null) {                try {                    throw new Exception(String.valueOf(ResultCode.UNAUTHENTICATED));               } catch (Exception e) {                    e.printStackTrace();               }                return  null;           }            String id = claims.getId();​            //5、添加用户请求头            request.mutate().header("userId",id).build();            return chain.filter(exchange);       }​        return chain.filter(exchange);   }​    @Override    public int getOrder() {        return 0;   }}10.4urifiler配置类@ConfigurationProperties(prefix = "urifiler", ignoreUnknownFields = false)@Data@Componentpublic class URIFilter {   private List<String> loginuri;}11.配置中心的使用访问http://127.0.0.1:30103/进入微服务本地引擎管理界面选择配置列表,创建配置项
  • [技术干货] 【深入浅出,Paas之路】华为云MVP田晓亮:企业向微服务架构转型的几点思考
    IDC的报告曾指出,到2021年,在超过一半的全球2000强企业中,平均1/3的数字化服务交互都将来自API开放生态系统,增长势头远超其自身的API交互能力。开放的API生态系统是企业数字化平台开放重构的关键。据悉,来自 Twitter、Netflix 和 Google 等公司的广受欢迎的公共 API 平均每天调用 10 亿到50亿次,API调用量逐渐成为一个开放平台成功的关键指标,哪些技术可以驱动API快速增长?拥有12年研发经验的田晓亮给出了他的答案。田晓亮现担任华为云微服务领域首席架构师,他也是国内早期服务网格实践者,曾自研服务网格作为云服务提供给客户业务使用。且听他娓娓道企业数字化转型的关键,以及系统性开展微服务化的一些重要举措。微服务为何如此重要?这里引用Smart Bear 2020年的API报告。如上图所示,微服务技术遥遥领先,成为最关键的领域技术,是企业API经济的技术基石。排在第二的DevOps相关技术则是微服务顺利落地的关键要素和前提。而微服务本身是一种架构模式,这也侧面证明了软件架构设计的价值。一款软件大部分的生命周期都处在维护期,不断地接受新需求,不断变化演进以满足需求。软件架构设计的主要目标便是支撑软件系统的全生命周期,设计良好的架构可以让系统便于理解、易于修改、方便维护,并且能轻松部署。软件架构的终极目标就是最大化程序员的生产力,同时最小化系统的总运营成本,微服务架构恰好能完美地达成这个目标。当然,有个题外话,研发人员也不必担心效率提升自己被优化,因为杰文斯悖论在这里也适用:技术进步提高单位人力利用效率,结果是增加而不是减少企业对人力的需求。是什么阻碍了微服务的应用接下来再看报告中另一个部分,是什么阻碍一个组织应用微服务?依次为:欠缺实践经验和技巧(或者我认为是不易雇佣相关人才);现存代码改造难;工作负担太重,没人(新的需求加入管道,它可以增加营收,此时如果老架构不是业务发展的障碍,就被搁置);IT成熟度不足、流程问题、基础设施问题;没预算;还没确定业务方向;缺少团队协作;缺少工具和技术。因为缺乏上述提到的这些东西,向微服务架构模式前进的企业可谓是千疮百孔。作为云服务提供商,或许可以帮助企业解决这些问题。田晓亮讲了一个他亲身经历的故事:我曾经拜访过一家企业,他们打算让业务团队在云上买些虚拟机自己搭建基础平台,被我阻拦了下来。因为当他们的业务增长后,会遇到各种各样的平台问题,但又没有相关的人才储备。当他们用开源的软件部署,遇到的生产问题其实需要开源社区的人来解决。而这个企业并没有清晰划分职责的技术组织。从商业视角出发,非主营核心业务通过外来购买付费服务来完成更为合适。另外他们也许进入了一个**的架构设计误区,在没有确定业务能力的情况下过早的进行了技术选型,而这个工作通常是要延后处理的,平台的维护成本可能会拖垮业务开发团队。通常情况下,大企业一般会使用云厂商提供的计算、存储等资源,也有自建IaaS服务或者两者并用的,然后在laaS层之上构建PaaS服务,为公司内部的业务服务。所以大型企业会清晰地拆分业务团队与基础设施团队,田晓亮本人就曾是基础设施团队的一员。在这种情况下,基础设施团队也是微服务架构模式的忠实用户。也就是说,他们不但要支撑好平台用户的微服务,自己也应用了该模式。基于多年的微服务转型经验,田晓亮提炼了几个可以帮助企业完成微服务数字化转型的关键点。如何系统性的展开微服务化我们可以围绕软件开发的速度,系统的安全和服务质量来构建微服务相关技术底座。再结合业务的实际发展,逐步转型微服务架构,不必在业务发展初期草草决定技术细节。匹配业务所需是否选择微服务架构模式应该从业务实际需求出发,企业先明确定义业务用例和策略,在此基础上进行架构方案的选择。对于一些刚刚起步的公司,单体应用也许就能满足业务需求。一切以快为准,当单体的开发效率比微服务高时,就果断的选择单体。而随着业务的扩大,企业可以通过绞杀者模式将单体应用向微服务架构模式迁移,进行单体应用绞杀的过程也称为应用现代化的过程。据维基百科,绞杀模式的使用场景是从单体应用平滑演进到微服务,将遗留应用程序转换为现代技术和技术栈的过程,也可称之为应用程序现代化。这种模式通常针对1个遗留应用系统,适合前期野蛮成长,业务增速较快的企业。整个改造流程不需要一步到位,一点点补充新的功能进入管道,比如有的功能可以增加营收,此时如果老架构不是企业业务发展的障碍,就可以被搁置并随时重启演进。具体策略有:新功能用新的微服务实现(阻止单体水平扩展和演进)隔离表示层和后端(降解单体)将现有的功能提取到微服务或者独立为微服务(降解单体)华为云CSE,解决分布式系统治理之难从单体成为微服务之后,假如没有成熟的工具配套,一切的成本都是翻倍提升的,这也是为什么说技术没有银弹。运行时的治理就是其中一个难题。华为云CSE的设计意图就是让企业的治理成本和门槛降低,以保障业务稳定健壮的运行,提供高质量API服务。CSE微服务引擎提供了基于业务视角的流量治理功能,使用可视化界面规划流量策略,无需关心微服务系统的复杂性。企业需要的只是定义好流量特征,比如登陆操作每分钟只能允许5次。另外使用Spring Cloud编程的应用可以无缝使用云上的能力,无需额外编码。CSE还提供了RBAC认证鉴权系统,提供基于标签的细粒度资源授权功能,可以规划多个账号,赋予角色和相关权限,保证多个团队协作过程中不会误操作或者访问不该访问的数据。这套认证系**立于华为云的IAM,类似MySQL的账号系统是完全独立的,这样团队之间就可以安全共享一套微服务引擎。微服务编程框架or服务网格,业务为王在进行编程框架和服务网格(Istio)之间的技术决策前,不妨先遵循架构设计阶段一个较好的指导思想——保留可选项,即尽可能推迟技术细节的相关决策。比如先确定业务能力是什么,收集用例,再决定选关系型数据库还是非关系型数据库,亦或是两者皆用。任何一种技术的选择皆如此。如在Spring Cloud这类编程框架和服务网格之间的选型存在疑虑时,就要充分的分析企业的业务是否匹配这些技术的适用场景,是否能支撑商业成果。因为选择什么技术手段支撑,终究要回归到业务本质来。企业要对多种可彼此替代的技术进行详尽的洞察和对比,结合需要支撑的业务场景做详尽的论证来验证最适合的技术到底是什么。下边这张表格列举了微服务开发下这两种技术方案的部分特性对比,它并不代表孰优孰劣,只是告诉企业要选择对应的能力来匹配业务、支撑业务。打个比方,Istio能提供绝对的内部网络通信安全,这是它独有的能力,如果企业的业务需要这样级别的防护,那么选择Istio管理会更加方便,而Istio却有很多不关心的维度,而这些维度正式编程框架提供的能力。管理好API如果API主要给外部系统调用,最好采用顶层设计的策略。不建议把这些对外暴露的API的设计权放到各个团队手中,因为最外层的、系统平台消费者可见的API必须是定义良好,风格一致的API,并且严格控制兼容性,可以使用CloudTest对这些API编写测试用例,并且在每次部署后,都执行一遍测试用例以确保平台的行为始终一致。API是业务的门面,可以采用Spring Cloud Gateway开发框架编写对外呈现的API,框架会自动生成Open API文档并注册到CSE微服务引擎实例中,这样可以重点审视API的定义,及时进行改进,高质量的交付所有的API。从DevOps文化建设入手当企业全面推动DevOps文化,并熟练让交付团队掌握相关工具后,微服务架构思维必然会在组织里萌芽。团队需要代码库,流水线等一系列服务来打造一条高效的生产线,故此DevOps技术因为其重要性排在了关键技术第二位。如果没有DevOps的成熟建设,就不要展开架构微服务化。华为云的DevCloud是集华为研发实践、前沿研发理念、先进研发工具为一体的研发云平台,面向开发者提供研发工具服务,让软件开发简单高效当然,系统性展开微服务化并非只有技术类工作,文化理念、团队合作形式、关键成员不断学习和精进都是微服务化的关键。总结简而言之,微服务架构满足了架构设计模式中的单一职责和共同闭包原则,它是业务和商业发展成规模化后的必经之路。微服务既符合架构设计原则,也能最小化系统运营成本,支撑高效的商业活动,在激烈的竞争中起到了“润滑剂”的作用。所以,你的业务是否已经准备好应用微服务了?
  • [热门活动] 【微服务直播 | 好礼多多】微服务快速开发利器之 Local CSE 活动火热进行中
    Local CSE是华为云微服务提供给广大开发者的本地轻量化微服务引擎,用于本地开发的轻量服务中心、配置中心,并提供简单的界面,开发者可以通过Local CSE零改造快速接入部署微服务,无需付费即可进行微服务开发,是广大开发者的微服务开发利器      如何简单接入Local CSE,零成本学习轻量化微服务引擎?如何多场景巧妙运用Local CSE?看华为云微服务高级工程师为开发者详解 Local CSE的服务注册与配置中心,手把手Local CSE实践教学…2022年开年直播微服务本地轻量化引擎 Local CSE利剑出鞘<直播时间>2月17日  19:00-20:00<直播嘉宾>昱霖 华为云微服务框架高级工程师Echo 华为云微服务产品经理<直播地址>微服务快速开发利器之 Local CSE直播预热活动,多重好礼等你来>>戳我,参与直播预热赢好礼<<好礼一:报名送码豆活动期间,成功报名直播并签到可获得200码豆。(限前500名)好礼二:参与邀请排行榜赢大奖邀请好友报名直播并签到赢荣耀Xsports运动蓝牙耳机/华为智能体脂秤 3 /华为mini蓝牙音箱等好礼注意:①人数相同时,以最先到达的为准;②若排名TOP1未达到最低有效邀请数量,则奖励顺延,例如:张三有效邀请量为799人,排名TOP1,则张三的奖励为华为智能体脂秤 3。邀请好友的具体操作流程如下:步骤一:邀请人成功报名活动后(点击去报名),点击图示中的“分享有礼”按钮 步骤二:通过生成的专属链接/邀请二维码,即可邀请好友报名活动。步骤三:好友报名直播后,点击“进入直播间”,填写签到问卷。有效邀请的定义(邀请的好友):所有被邀请人员需满足以下条件才可算成功邀请,纳入奖励数量:拥有华为云账号;2.回到直播间填写签到问卷。看直播,参与提问互动,奖品抽抽抽!1. 直播提问直播期间在“问答区”向专家提问,专家抽中问题进行答疑,抽中问题即可获得《持续演进的CloudNtive 云原生架构下微服务最佳实践]》书籍1本或华为云定制桌面鼠标垫1个(提问格式:手机号码后四位+问题,例:2333+如何零成本学习轻量化微服务引擎?)2. 直播抽奖直播期间,根据小助手在直播间提示的关键词口令进行抽奖,中奖即可获得《持续演进的CloudNtive 云原生架构下微服务最佳实践]》书籍1本或华为云定制桌面鼠标垫1个 [持续演进的CloudNtive 云原生架构下微服务最佳实践] [华为云定制桌面鼠标垫]更多好礼,更多精彩干货,尽在微服务直播间!2022年2月17日(周四)19:00-20:00我在直播间等你>> 扫码加入直播交流群 <<温馨提示:获奖用户将在2月24日16点前公布至本活动帖,请获奖用户在2022年3月3日15点前联系小助手(微信号:servicestage02)完善邮寄地址,过期未联系者视为自动放弃获奖奖品。活动奖品颜色随机,不接受指定,实物礼品将在活动结束后15个工作日内发货,码豆礼品将在活动结束后5个工作日内发放。本次活动一个实名认证账号只能对应一个获奖人,如同一账号填写多个不同获奖人,不予发放奖励;活动参与需遵守《华为社区常规活动规则》;华为云微服务拥有活动最终解释权。 华为云码豆怎么用?会员中心入口:https://devcloud.huaweicloud.com/bonususer/home码豆奖励活动规则:1)码豆可在码豆会员中心兑换实物礼品;2)码豆奖励将于活动结束后的3个工作日内充值到账,请到会员中心的“查看明细”中查看到账情况;3)码豆只能用于会员中心的礼品兑换,不得转让,具体规则请到会员中心阅读“码豆规则”;4)为保证码豆成功发放,如果修改过账号名还请向工作人员提供修改前后的账号名。
总条数:279 到第
上滑加载中