微服务解决方案 -- Spring Cloud Alibaba (九)服务网关

不了解此套教程的可以移步之前章节
1.微服务解决方案 – Spring Cloud Alibaba (一)服务的注册与发现
2.微服务解决方案 – Spring Cloud Alibaba (二)服务提供者
3.微服务解决方案 – Spring Cloud Alibaba (三)服务消费者(Feign)
4.微服务解决方案 – Spring Cloud Alibaba (四)服务熔断
5.微服务解决方案 – Spring Cloud Alibaba (五)分布式配置中心
6.微服务解决方案 – Spring Cloud Alibaba (六)Dubbo远程过程调用
7.微服务解决方案 – Spring Cloud Alibaba (七)Dubbo 服务提供者
8.微服务解决方案 – Spring Cloud Alibaba (八)Dubbo 服务消费者

服务网关


当服务开始变多,我们就要开始让服务聚合起来。前端访问我们的网关,网关路由到我们的服务提供者,这个服务提供者恰好是我们Dubbo的服务消费者,消费者消费Dubbo服务提供者,而只有我们的Dubbo才与数据库打交道。

知道大概原理,就要开始技术选型,其实没得选,只有zuul和Gateway。zuul已经不更新了,那只有Gateway

Spring Cloud Gateway


Spring Cloud Gateway 不使用 Web 作为服务器,而是使用 WebFlux 作为服务器 ,Gateway 项目已经依赖了starter-webflux,并不能依赖 starter-web

注意: 由于过滤器等功能依然需要 Servlet 支持,故可能还需要依赖 javax.servlet:javax.servlet-api

		<!-- Spring Boot -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <!-- Spring Cloud -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
        </dependency>
        <!-- Spring Cloud Alibaba -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <!-- Commons -->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
        </dependency>

启动类

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.gateway.discovery.DiscoveryClientRouteDefinitionLocator;
import org.springframework.cloud.gateway.discovery.DiscoveryLocatorProperties;
import org.springframework.cloud.gateway.route.RouteDefinitionLocator;
import org.springframework.context.annotation.Bean;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.codec.ServerCodecConfigurer;
import org.springframework.http.codec.support.DefaultServerCodecConfigurer;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.web.cors.reactive.CorsUtils;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebFilter;
import org.springframework.web.server.WebFilterChain;
import reactor.core.publisher.Mono;

/**
 * ProjectName:     MyShopPlus
 * Package:         com.laoshiren.myshop.plus.gateway
 * ClassName:       GatewayApplication
 * Author:          laoshiren
 * Description:
 * Date:            2020/1/13 16:30
 * Version:         1.0
 */
@SpringBootApplication
@EnableDiscoveryClient
public class GatewayApplication {

    private static final String ALL = "*";
    private static final String MAX_AGE = "3600L";
    @Bean
    public RouteDefinitionLocator discoveryClientRouteDefinitionLocator(DiscoveryClient discoveryClient, DiscoveryLocatorProperties properties) {
        return new DiscoveryClientRouteDefinitionLocator(discoveryClient, properties);
    }
    @Bean
    public ServerCodecConfigurer serverCodecConfigurer() {
        return new DefaultServerCodecConfigurer();
    }
    /**
     * 解决跨域
     */
    @Bean
    public WebFilter corsFilter() {
        return (ServerWebExchange ctx, WebFilterChain chain) -> {
            ServerHttpRequest request = ctx.getRequest();
            if (!CorsUtils.isCorsRequest(request)) {
                return chain.filter(ctx);
            }
            HttpHeaders requestHeaders = request.getHeaders();
            ServerHttpResponse response = ctx.getResponse();
            HttpMethod requestMethod = requestHeaders.getAccessControlRequestMethod();
            HttpHeaders headers = response.getHeaders();
            // 主要增加ACCESS_CONTROL_ALLOW_ORIGIN
            headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN, requestHeaders.getOrigin());
            headers.addAll(HttpHeaders.ACCESS_CONTROL_ALLOW_HEADERS, requestHeaders.getAccessControlRequestHeaders());
            if (requestMethod != null) {
                headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_METHODS, requestMethod.name());
            }
            headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_CREDENTIALS, "true");
            headers.add(HttpHeaders.ACCESS_CONTROL_EXPOSE_HEADERS, ALL);
            headers.add(HttpHeaders.ACCESS_CONTROL_MAX_AGE, MAX_AGE);
            if (request.getMethod() == HttpMethod.OPTIONS) {
                response.setStatusCode(HttpStatus.OK);
                return Mono.empty();
            }
            return chain.filter(ctx);
        };
    }
    
    public static void main(String[] args) {
        SpringApplication.run(GatewayApplication.class, args);
    }
}

如果在之前的Controller 加了@CrossOrigin(value = "*")的话,记得将其注释掉,否则会报 The 'Access-Control-Allow-Origin' header contains multiple values '*, *', but only one is allowed.

主要的配置文件

spring:
  cloud:
  # 路由网关配置
    gateway:
      discovery:
      # 采用服务名的路由策略
        locator:
          enabled: true
       # 配置路由规则
      routes:
        - id: nacos-provider
          # 采用 LoadBalanceClient 方式请求
          uri: lb://nacos-provider
          predicates:
            - Path=/web/echoprovider/**
          filters:
            # 此处配置去掉 1 个路径前缀,将nacos-provider这里去处,这样路由网关的路径就相对来说比较统一
            # 请求路径变成 http://ip:port/web/echoprovider/ 开始后面追加改provider的接口路径
            - StripPrefix=1

这样整套微服务的基础框架就算搭建完成了。

总结


回头看一下,我们服务注册与发现用的是Nacos,文件配置中心使用的也是Nacos
与数据库打交道我们用Dubbo的服务提供者,相当于整个项目作为数据库的dao层,使用高速序列化用Kryo
业务层我们使用Dubbo的服务消费者,配合Spring Cloud Nacos将该业务层作为服务提供者,对外提供RESTFul风格的接口。
将服务聚合我们使用Gateway

其中还有一些需要补足的地方,比如数据缓存(Redis),单点登录(OAuth2) ,数据查询(Solr,ES),分布式事务(Seata)和主键冲突(Leaf)等问题。

总之,基础框架搭建好后,整合其他的技术只要满足消费者/提供者模式即可。

发布了27 篇原创文章 · 获赞 4 · 访问量 902

猜你喜欢

转载自blog.csdn.net/weixin_42126468/article/details/104081682
今日推荐