吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 518|回复: 3
收起左侧

[学习记录] feign+nacos+gateway调用服务的配置

[复制链接]
FrozenAris 发表于 2024-8-27 09:31
本帖最后由 FrozenAris 于 2024-8-27 09:37 编辑

​
前言:学习java的项目时,用到了gateway网关+nacos注册服务+feign的调用链,但是在实际使用中时遇到了一些问题,尤其是配置网关和feign的时候,一定要配置上 超时时间,否则会因为超时时间过短,导致服务调用的线程还未结束就报错,在此记录一下;

一、spring-Cloud-gateway和nacos相关配置

1.首先,我们在项目中常见gateway的模块,引入依赖包,注意引入nacos的依赖,将gateway服务注册到nacos中
    <dependencies>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-alibaba-nacos-discovery</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
        </dependency>
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt</artifactId>
        </dependency>
    </dependencies>
       

2.配置文件:
重点注意要配置网关的链接超时时间、网关的拦截规则;
server:
  port: 6001
spring:
  application:
    name: leadnews-admin-gateway # nacos注册到nacos上服务的名称
  # 设置项目中nacos注册中心的所在地址
  cloud:
    nacos:
      discovery:
        server-addr: xxx.xxx.xxx.xxx:8848 # nacos所部署服务器的ip
    gateway:
      httpclient:
        connect-timeout: 50000 # 设置连接打开超时时间(ms)
        response-timeout: 100000 # 设置响应超时时间(ms)
      globalcors:
        cors-configurations:
          '[/**]': #匹配所有的请求
            allowedOrigins: "*" #解决跨域问题,允许所有域访问
            allowedMethods:
              - GET
              - POST
              - PUT
              - DELETE
      routes: # 配置网关拦截器的规则
        - id: user #对外部请求的url进行拦截,并处理其中的字段
          uri: lb://leadnews-user
           #截取url中的user部分,
          predicates :
           #注意配置等号两边不能有空格
           - Path=/user/**
           #截取的部分,设定只有第一段,也就是只有将请求url中的/user/ 替换成/leadnews_user/,并且将访问的端口6001转换成配置服务对应的端口
          filters:
          - StripPrefix=1
        - id: author #对外部请求的url进行拦截,并处理其中的字段
          uri: lb://leadnews-article
            #截取url中的admin部分,
          predicates :
            #注意配置等号两边不能有空格
          - Path=/author/**
            #截取的部分,设定只有第一段,也就是只有将请求url中的/auth/ 替换成/leadnews_user/,并且将访问的端口6001转换成配置服务对应的端口
          filters:
          - StripPrefix=1

                  
                  
3.编写springboot启动类
@SpringBootApplication
//此注解为注册到nacos服务的意思
@EnableDiscoveryClient
public class AdminGatewayApplication {
    public static void main(String[] args) {
        SpringApplication.run(AdminGatewayApplication.class,args);
    }

4.编写拦截器
@Component
@Log4j2
public class AuthorizeFilter implements GlobalFilter, Ordered {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        //1.获取请求对象和相应对象
        ServerHttpRequest request = exchange.getRequest();
        ServerHttpResponse response = exchange.getResponse();
        //2.验证其是否为登录请求,如果是登录请求则直接放行;
        if (request.getURI().getPath().contains("/login/in")){
            return chain.filter(exchange);
        }
        //3.如果不是登录,则获取jwt的数据,如果没有jwt,则返回报错给前台
        HttpHeaders headers = request.getHeaders();
        String token = headers.getFirst("token");
        if (StringUtils.isBlank(token)){
            response.setStatusCode(HttpStatus.UNAUTHORIZED);
            return response.setComplete();
        }
        try {
            //4.解析jwt数据中的参数
            Claims claims = AppJwtUtil.getClaimsBody(token);
            int result = AppJwtUtil.verifyToken(claims);
            if (result == -1|| result == 0){
                //判断token的有效期合法, 则蒋用户id赋值倒request中
                Integer id = (Integer) claims.get("id");
                log.info("获取到当前用户的id为:{},数据来源的url为:{}",id,request.getURI());
                ServerHttpRequest httpRequest = request.mutate().headers(httpHeaders -> {
                    httpHeaders.add("userId", id.toString());
                }).build();
                exchange.mutate().request(httpRequest).build();
            }
        } catch (Exception e){
            e.printStackTrace();
            response.setStatusCode(HttpStatus.UNAUTHORIZED);
            return response.setComplete();
        }
        //放行
        return chain.filter(exchange);
    }

    /**
     * 设置优先级的方法
     * 值越小,优先级越高
     * @return
     */
    @Override
    public int getOrder() {
        return 0;
    }
}

二、springboot 被调用服务的业务模块
1.首先创建模块,引入依赖包
<dependencies>
        <!-- 引入依赖模块 -->
        <!-- Spring boot starter -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <!-- 引入mybatis依赖-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
        </dependency>
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-alibaba-nacos-discovery</artifactId>
        </dependency>
    </dependencies>

2.配置application.yml
server:
  port: 9003
spring:
  application:
    name: leadnews-article
# 设置项目中nacos注册中心的所在地址
  cloud:
    nacos:
      discovery:
        server-addr: xxx.xxx.xxx.xxx:8848
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://xxx.xxx.xxx.xxx:3306/leadnews_article?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
    username: ****
    password: ****
# 设置Mapper接口所对应的XML文件位置,如果你在Mapper接口中有自定义方法,需要进行该配置
mybatis-plus:
  mapper-locations: classpath*:mapper/*.xml
  # 设置别名包扫描路径,通过该属性可以给包中的类注册别名
  type-aliases-package: article.pojos

3.编写springboot启动类
@SpringBootApplication
@EnableDiscoveryClient
@MapperScan(value = "com.***.article.mapper")
public class ArticleApplication {
    public static void main(String[] args) {
        SpringApplication.run(ArticleApplication.class, args);
    }
    //引入mybatiesPlus的分页组件
    @Bean
    PaginationInterceptor paginationInterceptor() {
        return new PaginationInterceptor();
    }
}

4.编写业务代码,主要是controller的代码,controller一定要使用restful风格的格式;service和mapper实现就不写了,具体业务自己再去写
@RestController
@RequestMapping("/api/v1/author")
public class ArticleAuthorController implements ArticleAuthorControllerApi {
    @Autowired
    private ArticleAuthorService articleAuthorService;

    @Override
    @GetMapping(value = "/findByUserId/{id}")
    //get请求参数要使用PathVariable注解
    public ApAuthor findByUserId(@PathVariable(value = "id") Integer id) {
        return articleAuthorService.findByUserId(id);
    }

    @PostMapping("/save")
    @Override
    //post请求的参数要使用RequestBody的注解
    public ResponseResult save(@RequestBody ApAuthor apAuthor) {
        articleAuthorService.save(apAuthor);
        return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
    }
}

三、使用Feign的调用服务的模块
1.引入依赖包
<dependencies>
        <!-- 引入依赖模块 -->
        <!-- Spring boot starter -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <!-- 引入mybatis依赖-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
        </dependency>
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
            <version>2.1.1.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-alibaba-nacos-discovery</artifactId>
        </dependency>
    </dependencies>

2.配置application.yml的配置
server:
  port: 9002
spring:
  cloud:
    nacos:
      discovery:
        server-addr: xxx.xx.xx.xx:8848
  application:
    name: leadnews-user
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://xxx.xxx.xx.xxx:3306/leadnews_user?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
    username: ****
    password: ****
# 设置Mapper接口所对应的XML文件位置,如果你在Mapper接口中有自定义方法,需要进行该配置
mybatis-plus:
  mapper-locations: classpath*:mapper/*.xml
  # 设置别名包扫描路径,通过该属性可以给包中的类注册别名
  type-aliases-package: com.***.model.user.pojos
feign:
  client:
    config:
      default:
        # 配置feign的链接超时时间,一定要配置上此项配置
        connectTimeout: 60000
        readTimeout: 60000

3.编辑springboot启动类
@SpringBootApplication
@EnableDiscoveryClient
@MapperScan("com.***.user.mapper")
//启动类中的feign配置
@EnableFeignClients
public class ApUserApplication {
    public static void main(String[] args) {
        SpringApplication.run(ApUserApplication.class,args);
    }
    //添加mybatis-plus分页组件插件
    @Bean
    public PaginationInterceptor paginationInterceptor(){
        return new PaginationInterceptor();
    }
}

4.编写feign的调用类
//注解里的value是被调用服务注册在nacos中的服务名称
@FeignClient("leadnews-article")
public interface ArticleFeign {
    //与被调用服务的rest请求类型保持一致,且要把调用url在注解里写全
    @GetMapping("/api/v1/author/findByUserId/{id}")
    public ApAuthor findByUserId(@PathVariable("id") Integer id);
    //与被调用服务的rest请求类型保持一致,且要把调用url在注解里写全
    @PostMapping("/api/v1/author/save")
    public ResponseResult save(@RequestBody ApAuthor apAuthor);
}

5.在业务service的impl中使用feign调用接口
@Autowired
    private ArticleFeign  articleFeign;
    private void createAuthor(WmUser wmUser) {
        ApAuthor author = articleFeign.findByUserId(wmUser.getApUserId());
        if (author == null){
            author.setUserId(wmUser.getApUserId());
            author.setWmUserId(wmUser.getId());
            author.setType(UserConstants.WEMEDIA_PERSION);
            author.setCreatedTime(new Date());
            articleFeign.save(author);
        }
    }


&#8203;

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

Kuronoks 发表于 2024-8-27 15:06
feign调用远端服务超时的意思吗?这样配置超时时间的意义是延缓问题?要是远端服务下次响应时间再延长了,那配置的超时时间不就又不够了?
fanliansuo1 发表于 2024-8-28 20:43
 楼主| FrozenAris 发表于 2024-9-2 20:01
Kuronoks 发表于 2024-8-27 15:06
feign调用远端服务超时的意思吗?这样配置超时时间的意义是延缓问题?要是远端服务下次响应时间再延长了, ...

是的,更改这个配置主要是因为时间太短,导致服务还没拉取到,就直接报错了,而你说得这远端服务响应时间过长,其实可以引用hystrix等熔断器进行处理
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-24 12:51

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表