SpringCloud学习笔记(二)

2023-11-02

续(一)

负载均衡的第二种实现方式Feign

前面在使用Ribbon + RestTemplate时,利用RestTemplate对Http请求的封装处理,形成了一套模板化的调用方法。,但是使用 RestTemplate 还是不方便,这样每次都调用 RestRemplate 的 API 太麻烦,我能不能像调用原来代码一样进行各个服务间的调用呢?那就用映射,就像域名和IP地址的映射。我们可以将被调用的服务代码映射到消费者端。所以,Feign在此基础上做了进一步的封装,由他来帮助我们定义和实现依赖服务接口的定义,在Feign的实现下,我们只需要创建一个接口并使用注解的方式来配置它 (类似以前Dao接口上标注Mapper注解,现在是一个微服务接口上面标注一个Feign注解),即可完成对服务提供方的接口绑定,简化了使用Spring Cloud Ribbon 时,自动封装服务调用客户端的开发量。

Feign,主要是社区版,大家都习惯面向接口编程。这个是很多开发人员的规范。调用微服务访问两种方法。
微服务名字 【ribbon】
接口和注解 【feign】
但是要注意的是,Feign集成了Ribbon,它下面用的还是Ribbon,只是进行了封装而已。

实现步骤

1:在基础的模块中导入依赖


        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-feign</artifactId>
            <version>1.4.6.RELEASE</version>
        </dependency>

2:创建一个接口,关联到我们的服务

package com.dongmu.service;

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.GetMapping;

@Component
@FeignClient(value = "SPRINGCLOUD-PROVIDER-DEPT")
public interface DeptService {

    @GetMapping("/api/dept")
    String getDept(Long id);

}

在这里插入图片描述

3:通过接口来调用我们的服务。

创建一个消费者,加入下面的依赖

<dependency>
            <groupId>org.example</groupId>
            <artifactId>springCloud-api</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-eureka</artifactId>
            <version>1.4.6.RELEASE</version>
        </dependency>

在消费者这种调用刚才接口里面的方法

package com.dongmu.controller;


import com.dongmu.service.DeptService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class DeptController {

    @Autowired
    DeptService deptService;


    @RequestMapping("rpc/getDept")
    public String rpcGetDept(Long id){
        return deptService.getDept(id);
    }
}

创建一个启动类

package com.dongmu;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.context.annotation.ComponentScan;

@SpringBootApplication
@ComponentScan("com.dongmu.*")
@EnableEurekaClient
@EnableFeignClients(basePackages = "com.dongmu.service")
public class ConsumerApplication_8802 {
    public static void main(String[] args) {
        SpringApplication.run(ConsumerApplication_8802.class,args);
    }
}

配置文件

server:
  port: 8802


eureka:
  client:
    register-with-eureka: false #不向eureka中注册自己,消费者只需要拿服务即可。
    service-url:
      defaultZone: http://localhost:7002/eureka/,http://localhost:7003/eureka/,http://localhost:7001/eureka/
#    fetch-registry: true #true表示去注册中心检索服务

启动进行访问(报错500)
记录一下错误地方,排错好久,哎、
在这里插入图片描述
通过8002访问成功,默认是轮询。修改负载均衡的方式和Ribbon是一样的,亲测。
在这里插入图片描述

Feign可以支持很多的自定义配置,如下表所示:

在这里插入图片描述
一般情况下,默认值就能满足我们使用,如果要自定义时,只需要创建自定义的@Bean覆盖默认Bean即可。

比如我们想要修改日志的级别,可以在配置文件里面按如下填写,当然,如果我们也可以使用注解的方式。

feign:  
  client:
    config: 
      userservice: # 针对某个微服务的配置,如果写default就是针对全局
        loggerLevel: FULL #  日志级别 

基于注解的方式,首先需要声明一个对象

public class DefaultFeignConfiguration  {
    @Bean
    public Logger.Level feignLogLevel(){
        return Logger.Level.BASIC; // 日志级别为BASIC
    }
}

如果需要全局生效,就放在主启动类的@EnableFeignClients这个注解中:

@EnableFeignClients(defaultConfiguration = DefaultFeignConfiguration .class) 

如果是局部生效,则把它放到对应的@FeignClient这个注解中:

@FeignClient(value = "userservice", configuration = DefaultFeignConfiguration .class) 

另外,Feign只是一种风格,底层还是调用了http请求,底层使用的是URLConnection,不支持连接池,效率比较低,我们可以使用ApacheHttpClient或者OKHttp,这两种都支持连接池。我们使用的时候替换默认的http请求工具即可。使用方式如下

  • 首先引入依赖
<!--httpClient的依赖 -->
<dependency>
    <groupId>io.github.openfeign</groupId>
    <artifactId>feign-httpclient</artifactId>
</dependency>
  • 配置连接池
feign:
  client:
    config:
      default: # default全局的配置
        loggerLevel: BASIC # 日志级别,BASIC就是基本的请求和响应信息
  httpclient:
    enabled: true # 开启feign对HttpClient的支持
    max-connections: 200 # 最大的连接数
    max-connections-per-route: 50 # 每个路径的最大连接数

断路器——Netflix Hystrix

在介绍Hystrix之前,我们先了解一些基本的概念

雪崩效应

在微服务架构中,为了保证其高可用,单个服务通常会集群部署。由于网络原因或者自身的原因,服务并不能保证100%可用,如果单个服务出现问题,调用这个服务就会出现线程阻塞,此时若有大量的请求涌入,Servlet容器的线程资源会被消耗完毕,导致服务瘫痪。如客户端访问 A 服务,而 A 服务需要调用 B 服务,B 服务需要调用 C 服务,由于网络原因或者自身的原因,如果 B 服务或者 C 服务不能及时响应,A 服务将处于阻塞状态,直到 B 服务 C 服务响应。此时若有大量的请求涌入,容器的线程资源会被消耗完毕,导致服务瘫痪。服务与服务之间的依赖性,故障会传播,造成连锁反应,会对整个微服务系统造成灾难性的严重后果,这就是服务故障的“雪崩”效应。

造成雪崩的原因可以归结为以下三点:

  • 服务提供者不可用(硬件故障,程序 BUG,缓存击穿,用户大量请求等)
  • 重试加大流量(用户重试,代码逻辑重试)
  • 服务消费者不可用(同步等待造成的资源耗尽)

最终的结果就是:一个服务不可用,导致一系列服务的不可用。

Netflix Hystrix是SOA/微服务架构中提供服务隔离、熔断、降级机制的工具/框架。Netflix Hystrix是断路器的一种实现,用于高微服务架构的可用性,是防止服务出现雪崩的利器。。
雪崩是系统中的蝴蝶效应导致,其发生的原因多种多样,从源头我们无法完全杜绝雪崩的发生,但是雪崩的根本原因来源于服务之间的强依赖,所以我们可以提前评估做好服务容错。解决方案大概可以分为以下几种:

  • 请求缓存:支持将一个请求与返回结果做缓存处理;
  • 请求合并:将相同的请求进行合并然后调用批处理接口;
  • 服务隔离:限制调用分布式服务的资源,某一个调用的服务出现问题不会影响其他服务调用;
  • 服务熔断:牺牲局部服务,保全整体系统稳定性的措施;
  • 服务降级:服务熔断以后,客户端调用自己本地方法返回缺省值。降级是为了更好的用户体验,当一个方法调用异常时,通过执行另一种代码逻辑来给用户友好的回复。对应着 Hystrix 的后备处理模式

参考文章,叙述非常清楚

服务熔断

1:先创建一个服务提供者,方式和之前普通的方式一样,
然后加入依赖

<!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-eureka -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-eureka</artifactId>
            <version>1.4.7.RELEASE</version>
        </dependency>

2:编写我们的服务

package com.dongmu.controller;

import com.dongmu.dao.DeptMapper;
import com.dongmu.pojo.Dept;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.ribbon.proxy.annotation.Hystrix;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
package com.dongmu.controller;

import com.dongmu.dao.DeptMapper;
import com.dongmu.pojo.Dept;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.ribbon.proxy.annotation.Hystrix;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class DeptController {

    @Autowired
    DeptMapper deptMapper;

    @ResponseBody
    @PostMapping("/deptAdd")
    public String addDept(){
        Dept dept = new Dept("测试部"+System.currentTimeMillis());
        deptMapper.insertSelective(dept);

        return dept.toString();
    }


    @ResponseBody
    @GetMapping("/deptGet")
    @HystrixCommand(fallbackMethod = "hystrixGet")
    public String gerDept(@RequestParam(value = "id") Long id){

//        dept.setDeptno(id);
        Dept dept = deptMapper.selectByPrimaryKey(id);

        if (dept==null){
            throw new RuntimeException("不存在这个用户,请重新输入。");
        }

        return dept.toString();
    }

    //发送异常的备选方法
    public String hystrixGet(@RequestParam(value = "id") Long id){
        return "不存在这个用户,请重新输入。_Hystrix";
    }
}

  • @HystrixCommand(fallbackMethod = “hystrixGet”)就是我们方法返回失败了执行其他的方法。服务熔点。

4:主启动类上添加对熔断的支持

package com.dongmu;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.ComponentScan;

@SpringBootApplication
@ComponentScan("com.dongmu.*")
@EnableEurekaClient
@EnableCircuitBreaker//添加对熔断的支持,就是断路器
public class ProviderApplication_8004 {
    public static void main(String[] args) {

        ConfigurableApplicationContext run = SpringApplication.run(ProviderApplication_8004.class, args);
    }
}

启动项目进行测试:
在这里插入图片描述

采用轮询,可以发现其他的服务会出现异常,但是这个服务对请求进行了熔断。

服务降级

1:在基础模块里面加入下面这个类

package com.dongmu.service;

import feign.hystrix.FallbackFactory;
import org.springframework.stereotype.Component;


@Component
/*
FallbackFactory可以用来处理我们失败的回调
 */
public class DeptServiceFallBackFactory implements FallbackFactory {
    @Override
    //返回值表示我们要处理的类,直接一下子处理一个类中所有的方法。
    public DeptService create(Throwable throwable) {
        return new DeptService() {
            @Override
            public String getDept(Long id) {
                return "服务降级执行的服务。";
            }
        };
    }
}

2:在我们刚才的feign里面添加一个注解的属性,指定我们失败回调的类的class

package com.dongmu.service;

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;

@Component
@FeignClient(value = "SPRINGCLOUD-PROVIDER-DEPT",fallbackFactory = DeptServiceFallBackFactory.class)
public interface DeptService {

    @GetMapping("/api/deptGet")
    String getDept(@RequestParam( value = "id") Long id);

}

在这里插入图片描述

3:在feign的消费者端开启服务降级的支持。

server:
  port: 8802


eureka:
  client:
    register-with-eureka: false #不向eureka中注册自己,消费者只需要拿服务即可。
    service-url:
      defaultZone: http://localhost:7002/eureka/,http://localhost:7003/eureka/,http://localhost:7001/eureka/
    #fetch-registry: true #true表示去注册中心检索服务


feign:
  hystrix:
    enabled: true

然后启动服务,继续访问
注意:我们刚才的服务熔断是在服务端进行的,写了另一个处理失败调用的方法,但是这里服务降级我们没有在服务端进行任何操作,仅仅是在消费者端进行了一些配置

在这里插入图片描述
在这里插入图片描述

可以发现,在访问其他三个服务器的时候执行了服务降级的处理,在执行第四个服务器中进行了服务熔断的处理的地方,返回了服务熔断的处理。

我们查询正常存在的数据
在这里插入图片描述
在这里插入图片描述
都可以访问,这时候我们把服务1关掉,它还是会走其他的请求,我们把四个服务全都关闭,再进行访问,出现服务降级。只要还有针对于这个请求可以用的服务就不会出现服务降级,我们要把所有的服务全部关闭就可以看到服务降级。
在这里插入图片描述

服务熔断和降级的区别联系

  • 服务熔断一般是某个服务(下游服务)故障引起,而服务降级一般是从整体负荷考虑;
  • 目的很一致,都是从可用性可靠性着想,为防止系统的整体缓慢甚至崩溃,采用的技术手段;
  • 服务熔断:一般是某个服务异常引起的,相当于“保险丝”,当某个异常条件被触发,直接熔断整个服务,不是等到此服务超时
  • 服务降级:降级一般是从整体负荷考虑,当某个服务熔断之后,服务器将不再被调用,客户端可自己准备一个本地的fallback回调,返回一个缺省值,虽然服务水平下降,但是能用,比直接挂掉要强

Dashboard监控页面

1:创建一个监控模块添加依赖

<!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-eureka -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-hystrix</artifactId>
            <version>1.4.7.RELEASE</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-eureka -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-hystrix-dashboard</artifactId>
            <version>1.4.7.RELEASE</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-eureka -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-eureka</artifactId>
            <version>1.4.6.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>org.example</groupId>
            <artifactId>springCloud-api</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
        </dependency>

同时注意保证服务端要含有这个依赖

<!--这个包可以帮助我们配置当前这个服务在Eureka中监控页面的信息-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>

2:配置一个端口

server:
  port: 8803

3:添加启动类,开启监控支持

package com.dongmu;


import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.hystrix.dashboard.EnableHystrixDashboard;

@SpringBootApplication
@EnableHystrixDashboard//开启监控支持
public class HystrixDashBoardApplication {

    public static void main(String[] args) {
        SpringApplication.run(HystrixDashBoardApplication.class,args);
    }
}

启动进行访问
在这里插入图片描述

访问成功。

在添加了熔断机制的服务者启动类中进行注册

@Bean
    public ServletRegistrationBean registrationBean(){
        ServletRegistrationBean registrationBean = new ServletRegistrationBean<>(new HystrixMetricsStreamServlet());
        registrationBean.addUrlMappings("/actuator/hystrix.stream");

        return  registrationBean;
    }

在这里插入图片描述
注意这个路径要带上自己的项目名
进入监视页面,第三个空名字只是给这个监控起一个名字
在这里插入图片描述
登录进入之后我们一边刷新访问一遍观察监控页面
在这里插入图片描述

在这里插入图片描述

服务网关——Netflix Zuul

什么是Zuul?

API网关为微服务架构中的服务提供了统一的访问入口,客户端通过API网关访问相关服务。API网关的定义类似于设计模式中的门面模式,它相当于整个微服务架构中的门面,所有客户端的访问都通过它来进行路由及过滤。
zuul 是netflix开源的一个API Gateway 服务器, 本质上是一个web servlet应用。Zuul 在云平台上提供动态路由,监控,弹性,安全过滤等边缘服务的框架。主要功能如下:

  • 权限、身份认证
  • 动态路由负载均衡
  • 请求限流

使用步骤
1:创建一个路由模块添加依赖

<!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-eureka -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-zuul</artifactId>
            <version>1.4.7.RELEASE</version>
        </dependency>


        <!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-eureka -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-hystrix</artifactId>
            <version>1.4.7.RELEASE</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-eureka -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-hystrix-dashboard</artifactId>
            <version>1.4.7.RELEASE</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-eureka -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-eureka</artifactId>
            <version>1.4.6.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>org.example</groupId>
            <artifactId>springCloud-api</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
        </dependency>

2:配置文件

server:
  port: 9527

spring:
  application:
    name: springcloud-zuul

eureka:
  client:
    service-url:
      #这里写远程注册中心的地址,由于测试的时候注册中心就在本机所以写的是localhost
      defaultZone: http://localhost:7001/eureka/,http://localhost:7002/eureka/,http://localhost:7003/eureka/
  instance:
      #这个会显示再远程eureka的面板上
    instance-id: Zuul_9527.com
    prefer-ip-address: true


info:
  app.name: DONGMU_SpringCloud
  company.name: BEIHAI

3:启动类

package com.dongmu;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;

@SpringBootApplication
@EnableZuulProxy
public class ZuulApplication {
    public static void main(String[] args) {
        SpringApplication.run(ZuulApplication.class,args);
    }
}

启动查看eureka注册中心

在这里插入图片描述
可以看到服务已经成功了。然后我们直接通过路由访问注册中心的服务。
在这里插入图片描述

但是这个里面会暴露我们服务的名字,我们在zuul的配置文件中添加


zuul:
  routes:
    mydept.serviceId: springcloud-provider-dept
    mydept.path: /dept/**

然后把服务名字换成dept来访问
在这里插入图片描述
但是存在一个问题,就是原来的路径还是能够访问。
在这里插入图片描述
我们继续添加配置

zuul:
  routes:
    mydept.serviceId: springcloud-provider-dept
    mydept.path: /dept/**
  ignored-services:
    - springcloud-provider-dept

之后就无法访问了。
在这里插入图片描述
修改的路径依然能够访问
在这里插入图片描述
网关配置断言

spring:
  application:
    name: gateway # 服务名称
  cloud:
    nacos:
      server-addr: localhost:8848 # nacos地址
    gateway:
      routes: # 网关路由配置
        - id: user-service # 路由id,自定义,只要唯一即可
          # uri: http://127.0.0.1:8081 # 路由的目标地址 http就是固定地址
          uri: lb://userservice # 路由的目标地址 lb就是负载均衡,后面跟服务名称
          predicates: # 路由断言,也就是判断请求是否符合路由规则的条件
            - Path=/user/** # 这个是按照路径匹配,只要以/user/开头就符合要求

我们在配置文件中写的断言规则只是字符串,这些字符串会被Predicate Factory读取并处理,转变为路由判断的条件。
例如Path=/user/**是按照路径匹配,这个规则是由org.springframework.cloud.gateway.handler.predicate.PathRoutePredicateFactory类来处理的,像这样的断言工厂在SpringCloudGateway还有十几个,大家可以自行百度。

过滤器工厂

GatewayFilter是网关中提供的一种过滤器,可以对进入网关的请求和微服务返回的响应做处理。Spring提供了31种不同的路由过滤器工厂,例如

名称 说明
AddRequestHeader 给当前请求添加一个请求头
RemoveRequestHeader 移除请求中的一个请求头
AddResponseHeader 给响应结果中添加一个响应头
RemoveResponseHeader 从响应结果中移除有一个响应头
RequestRateLimiter 限制请求的流量

使用方式如下:

spring:
  cloud:
    gateway:
      routes:
      - id: user-service 
        uri: lb://userservice 
        predicates: 
        - Path=/user/** 
        filters: # 过滤器
        - AddRequestHeader=Truth, Itcast is freaking awesome! # 添加请求头

如果要对所有的路由都生效,则可以将过滤器工厂写到default下。格式如下:

spring:
  cloud:
    gateway:
      routes:
      - id: user-service 
        uri: lb://userservice 
        predicates: 
        - Path=/user/**
      default-filters: # 默认过滤项
      - AddRequestHeader=Truth, Itcast is freaking awesome! 

全局过滤器

全局过滤器的作用也是处理一切进入网关的请求和微服务响应,与GatewayFilter的作用一样。区别在于GatewayFilter通过配置定义,处理逻辑是固定的;而GlobalFilter的逻辑需要自己写代码实现。

定义方式是实现GlobalFilter接口。

public interface GlobalFilter {
    /**
     *  处理当前请求,有必要的话通过{@link GatewayFilterChain}将请求交给下一个过滤器处理
     *
     * @param exchange 请求上下文,里面可以获取Request、Response等信息
     * @param chain 用来把请求委托给下一个过滤器 
     * @return {@code Mono<Void>} 返回标示当前过滤器业务结束
     */
    Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain);
}

网关解决跨域问题

spring:
  cloud:
    gateway:
      # 。。。
      globalcors: # 全局的跨域处理
        add-to-simple-url-handler-mapping: true # 解决options请求被拦截问题
        corsConfigurations:
          '[/**]':
            allowedOrigins: # 允许哪些网站的跨域请求 
              - "http://localhost:8090"
            allowedMethods: # 允许的跨域ajax的请求方式
              - "GET"
              - "POST"
              - "DELETE"
              - "PUT"
              - "OPTIONS"
            allowedHeaders: "*" # 允许在请求中携带的头信息
            allowCredentials: true # 是否允许携带cookie
            maxAge: 360000 # 这次跨域检测的有效期

参考视频1
参考视频2

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

SpringCloud学习笔记(二) 的相关文章

  • 如何循环遍历所有组合,例如48 选择 5 [重复]

    这个问题在这里已经有答案了 可能的重复 如何在java中从大小为n的集合中迭代生成k个元素子集 https stackoverflow com questions 4504974 how to iteratively generate k
  • 动态选择端口号?

    在 Java 中 我需要获取端口号以在同一程序的多个实例之间进行通信 现在 我可以简单地选择一些固定的数字并使用它 但我想知道是否有一种方法可以动态选择端口号 这样我就不必打扰我的用户设置端口号 这是我的一个想法 其工作原理如下 有一个固定
  • 如何获取之前的URL?

    我需要调用我的网络应用程序的 URL 例如 如果有一个从 stackoverflow com 到我的网站 foo com 的链接 我需要 Web 应用程序 托管 bean 中的 stackoverflow 链接 感谢所有帮助 谢谢 并不总是
  • java.lang.IllegalStateException:应用程序 PagerAdapter 更改了适配器的内容,而没有调用 PagerAdapter#notifyDataSetChanged android

    我正在尝试使用静态类将值传递给视图 而不是使用意图 因为我必须传递大量数据 有时我会收到此错误 但无法找出主要原因是什么 Error java lang IllegalStateException The application s Pag
  • Eclipse Maven Spring 项目 - 错误

    I need help with an error which make me crazy I started to study Java EE and I am going through tutorial on youtube Ever
  • 像 Java 这样的静态类型语言中动态方法解析背后的原因是什么

    我对 Java 中引用变量的动态 静态类型和动态方法解析的概念有点困惑 考虑 public class Types Override public boolean equals Object obj System out println i
  • 当 OnFocusChangeListener 应用于包装的 EditText 时,TextInputLayout 没有动画

    不能比标题说得更清楚了 我有一个由文本输入布局包裹的 EditText 我试图在 EditText 失去焦点时触发一个事件 但是 一旦应用了事件侦听器 TextInputLayout 就不再对文本进行动画处理 它只是位于 editText
  • tomcat 中受密码保护的应用程序

    我正在使用 JSP Servlet 开发一个Web应用程序 并且我使用了Tomcat 7 0 33 as a web container 所以我的要求是tomcat中的每个应用程序都会password像受保护的manager applica
  • logcat 中 mSecurityInputMethodService 为 null

    我写了一点android应显示智能手机当前位置 最后已知位置 的应用程序 尽管我复制了示例代码 并尝试了其他几种解决方案 但似乎每次都有相同的错误 我的应用程序由一个按钮组成 按下按钮应该log经度和纬度 但仅对数 mSecurityInp
  • 获取文件的总大小(以字节为单位)[重复]

    这个问题在这里已经有答案了 可能的重复 java 高效获取文件大小 https stackoverflow com questions 116574 java get file size efficiently 我有一个名为 filenam
  • 使用 AsyncTask 传递值

    我一直在努力解决这个问题 但我已经到了不知道该怎么办的地步 我想做的是使用一个类下载文件并将其解析为字符串 然后将该字符串发送到另一个类来解析 JSON 内容 所有部件都可以单独工作 并且我已经单独测试了所有部件 我只是不知道如何将值发送到
  • Eclipse 启动时崩溃;退出代码=13

    I am trying to work with Eclipse Helios on my x64 machine Im pretty sure now that this problem could occur with any ecli
  • 干净构建 Java 命令行

    我正在使用命令行编译使用 eclipse 编写的项目 如下所示 javac file java 然后运行 java file args here 我将如何运行干净的构建或编译 每当我重新编译时 除非删除所有内容 否则更改不会受到影响 cla
  • 如何使用mockito模拟构建器

    我有一个建造者 class Builder private String name private String address public Builder setName String name this name name retur
  • 包 javax.el 不存在

    我正在使用 jre6 eclipse 并导入 javax el 错误 包 javax el 不存在 javac 导入 javax el 过来 这不应该是java的一部分吗 谁能告诉我为什么会这样 谢谢 米 EL 统一表达语言 是 Java
  • 在java中为组合框分配键

    我想添加一个JComboBox在 Swing 中这很简单 但我想为组合中的每个项目分配值 我有以下代码 JComboBox jc1 new JComboBox jc1 addItem a jc1 addItem b jc1 addItem
  • 长轮询会冻结浏览器并阻止其他 ajax 请求

    我正在尝试在我的中实现长轮询Spring MVC Web 应用程序 http static springsource org spring docs 2 0 x reference mvc html但在 4 5 个连续 AJAX 请求后它会
  • 使用 svn 1.8.x、subclise 1.10 的 m2e-subclipse 连接器在哪里?

    我读到 m2e 的生产商已经停止生产 svn 1 7 以外的任何版本的 m2e 连接器 Tigris 显然已经填补了维护 m2e subclipse 连接器的空缺 Q1 我的问题是 使用 svn 1 8 x 的 eclipse 更新 url
  • 如果没有抽象成员,基类是否应该标记为抽象?

    如果一个类没有抽象成员 可以将其标记为抽象吗 即使没有实际理由直接实例化它 除了单元测试 是的 将不应该实例化的基类显式标记为抽象是合理且有益的 即使在没有抽象方法的情况下也是如此 它强制执行通用准则来使非叶类抽象 它阻止其他程序员创建该类
  • Spring Boot 无法更新 azure cosmos db(MongoDb) 上的分片集合

    我的数据库中存在一个集合 documentDev 其分片键为 dNumber 样本文件 id 12831221wadaee23 dNumber 115 processed false 如果我尝试使用以下命令通过任何查询工具更新此文档 db

随机推荐

  • 用jquery插件实现漂亮的日历效果

  • python爬虫时,将时间戳转换成北京时间、标准格式

    import time timestamp items get created 时间戳 time local time localtime int timestamp 注意 这里的整数不能超过11位数 pub date time strft
  • vue点击按钮次数

    显示点击次数
  • blender常用快捷键+动效制作

    文章目录 1 技术概述 2 技术详述 2 1常用快捷键 2 2镜像循环动画效果 3 遇到的难点和解决办法 难点 解决方法 4 总结 1 技术概述 Blender是一款免费的3D计算机图形软件 可用于创建动画 视觉效果 游戏开发和建筑设计等领
  • 分布式系统之Raft算法

    介绍 Raft是一种为了管理日志复制的分布式一致性算法 Raft 出现之前 Paxos 一直是分布式一致性算法的标准 Paxos 难以理解 更难以实现 Raft 的设计目标是简化 Paxos 使得算法既容易理解 也容易实现 Paxos 和
  • 【opencv学习之二十四】OpenCV滤波处理对比

    OpenCV的邻域滤波处理函数主要都通图像的卷积操作 有 1方框滤波boxFilter 属于线性滤波 其原理是用一个矩阵和一个核矩阵卷积操作 2均值滤波blur 也属于线性滤波 是方框滤波一种归一化后的方框滤波 3高斯滤波GaussianB
  • HTML+CSS+JavaScript+JQuery+Ajax

    HTML 1 DTD定义了HTML和XHTML的语义约束 包括HTML文档中可以出现哪些元素 各元素支持哪些属性等 2 基本的HTML文档 页面内容部分 不要在和之间插入任何内容 不要再和之间插入任何内容 不要在
  • Matlab模糊控制的模糊曲面构成怎么看?

    第一种方法 用matlab自带的模糊控制器 1 在MATLAB命令窗口输入fuzzy 然后在弹出框点 File Import From File 2 在Fuzzy Logic Designer 中点击 View Suface 但是 用这种方
  • VSCode用私钥连服务器

    以前一直用PyCharm 听说VSCode可以连接服务器直接修改文件什么的很方便 于是改用VSCode试试 记录一下自己的具体配置流程 1 安好VSCode后 打开左侧栏的扩展 搜索ssh 安装Remote SSH 2 安装后左侧栏出现远程
  • 【LlamaIndex 教程】一文看懂LlamaIndex用法,为LLMs学习私有知识

    城南 LlamaIndex 教程 一文看懂LlamaIndex用法 为LLMs学习私有知识 我是卷了又没卷 薛定谔的卷的AI算法工程师 陈城南 全网平台同名 担任某大厂的算法工程师 带来最新的前沿AI知识 分享 AI 有趣工具和实用玩法 包
  • vue3实现高德地图多点标注(so easy)

    vue3实现高德地图多点标注 so easy 前言 思路清晰 抽丝剥茧 必要的准备工作 最简单的部分 处理数据之前 最关键的思路 效果 完整代码 前言 非常感谢你能打开这篇博客 我想你一定是遇到了地图多点标注有关的问题 这些问题对你造成一些
  • 04 Java面试题之数组

    一 数组的类型可以为任意类型吗 答 可以是任意类型 二 数组中的元素的类型必须是相同的吗 数组中的元素是有序的吗 答 数组中元素的类型必须是相同的 数组中元素是有序的 索引的顺序 从零开始 三 数组的长度可变不 数组的长度使用哪个属性 答
  • 深度学习|卷积神经网络

    一 卷积神经网络简介 卷积神经网络 Convolutional Neural Network CNN 是一种深度学习神经网络结构 主要用于图像识别 计算机视觉等领域 该结构在处理图像等高维数据时表现出色 因为它具有共享权重和局部感知的特点
  • Yii Framework 开发教程(12) UI 组件 ClipWidget示例

    CClipWidget提供了类似录制 宏 的功能 定义在CClipWidget的init和run之间的内容可以存放在Controller的Clip变量中 然后重新回放到任意其它位置 CClipWidget封装的是CBaseControlle
  • html随机点名函数,利用JS实现课堂随机点名和顺序点名

    1 效果 ScreenGif gif 2 Html代码 随机点名区域 3 JavaScript代码 var i 0 t用来接收setTimeOut 的返回值 var t var st 张三 李四 老王 旺财 铁柱 王八 来福 小明 小红 狗
  • 时域OCT与频域OCT的区别

    时域OCT TD OCT 与频域OCT FD OCT 的最大区别在于信号采集单元 也就是检测器部分 时域 用光电探测器进行点探测 频域 用光谱仪进行光谱的采集 一般多用光栅和线阵CCD阵列为核心的小型光谱仪 按照分光原件不同分的 1 1 g
  • 类文件具有错误的版本 55.0, 应为 52.0

    文章目录 背景 原因 解决方案 方案一 条件 使用idea本身maven的编译命令的话 使用命令编译的话 mac怎么查看安装的jdk目录 mac怎么修改默认是jdk11 1 evanyang Evans MacBook Pro vim ba
  • 在ubuntu中安装Jenkins

    安装前的准备 一台 ubuntu 主机 本篇文章使用的是Ubuntu 16 04 5 LTS 切换到root用户 安装 Jenkins 第一次安装的可以稍微看下jenkins 的安装文档 总之 如果没有安装 Java 需要安装一下 下面是目
  • pickle库的使用

    pickle 作用 把一个列表 迭代类型变量 存储为序列化对象 不以字符串存 而是以序列存 存好后下次取出依旧是列表 迭代类型变量 意义 即把迭代变量保存到硬盘中 而不只是存在内存里 可以方便直接提供给他人一个变量而不用给比人一整段代码 存
  • SpringCloud学习笔记(二)

    续 一 负载均衡的第二种实现方式Feign 前面在使用Ribbon RestTemplate时 利用RestTemplate对Http请求的封装处理 形成了一套模板化的调用方法 但是使用 RestTemplate 还是不方便 这样每次都调用