Getting Started with Microservices---SpringCloud (2)

Getting Started with Microservices---SpringCloud (2)

1.Nacos configuration management

In addition to being a registration center, Nacos can also be used for configuration management.

1.1. Unified configuration management

When more and more instances of microservices are deployed, reaching tens or hundreds, modifying the configuration of microservices one by one will be frustrating and error-prone. We need a unified configuration management solution that can centrally manage the configuration of all instances.

Insert image description here

On the one hand, Nacos can centrally manage configurations, and on the other hand, it can promptly notify microservices when configuration changes to achieve hot updates of configurations.

1.1.1. Add configuration file in nacos

How to manage configuration in nacos?
Insert image description here

Then fill in the configuration information in the pop-up form:
Insert image description here

Note: The core configuration of the project needs to be hot-updated before it is necessary to put it into nacos management. Some configurations that rarely change are better stored locally in the microservice.

1.1.2. Pull configuration from microservices

The microservice must pull the configuration managed in nacos and merge it with the local application.yml configuration to complete the project startup.

But if application.yml has not been read, how to know the nacos address?

Therefore, spring introduces a new configuration file: the bootstrap.yaml file, which will be read before application.yml. The process is as follows:
Insert image description here

1) Introduce nacos-config dependency

First, in the user-service service, introduce the client dependency of nacos-config:

<!--nacos配置管理依赖-->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>

2) Add bootstrap.yaml

Then, add a bootstrap.yaml file in user-service with the following content:

spring:
  application:
    name: userservice # 服务名称
  profiles:
    active: dev #开发环境,这里是dev 
  cloud:
    nacos:
      server-addr: localhost:8848 # Nacos地址
      config:
        file-extension: yaml # 文件后缀名

Here, the nacos address will be obtained based on spring.cloud.nacos.server-addr, and then based on

${spring.application.name}-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}As the file id, read the configuration.

In this case, it is to read userservice-dev.yaml:
Insert image description here

3) Read nacos configuration

Add business logic to UserController in user-service and read the pattern.dateformat configuration:
Insert image description here

Complete code:

package cn.itcast.user.web;

import cn.itcast.user.pojo.User;
import cn.itcast.user.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

@Slf4j
@RestController
@RequestMapping("/user")
public class UserController {
    
    

    @Autowired
    private UserService userService;

    @Value("${pattern.dateformat}")
    private String dateformat;
    
    @GetMapping("now")
    public String now(){
    
    
        return LocalDateTime.now().format(DateTimeFormatter.ofPattern(dateformat));
    }
    // ...略
}

When accessing the page, you can see the effect:
Insert image description here

1.2. Configure hot update

Our ultimate goal is to modify the configuration in nacos so that the configuration can take effect in the microservice without restarting, that is, configuration hot update .

To implement hot update of configuration, two methods can be used:

1.2.1. Method 1

Add the annotation @RefreshScope to the class where the variable injected by @Value is located:
Insert image description here

1.2.2. Method 2

Use @ConfigurationProperties annotation instead of @Value annotation.

In the user-service service, add a class and read the pattern.dateformat attribute:

package cn.itcast.user.config;

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

@Component
@Data
@ConfigurationProperties(prefix = "pattern")
public class PatternProperties {
    
    
    private String dateformat;
}

Use this class instead of @Value in UserController:
Insert image description here

Complete code:

package cn.itcast.user.web;

import cn.itcast.user.config.PatternProperties;
import cn.itcast.user.pojo.User;
import cn.itcast.user.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

@Slf4j
@RestController
@RequestMapping("/user")
public class UserController {
    
    

    @Autowired
    private UserService userService;

    @Autowired
    private PatternProperties patternProperties;

    @GetMapping("now")
    public String now(){
    
    
        return LocalDateTime.now().format(DateTimeFormatter.ofPattern(patternProperties.getDateformat()));
    }

    // 略
}

1.3.Configuration sharing

In fact, when the microservice starts, it will go to nacos to read multiple configuration files, for example:

  • [spring.application.name]-[spring.profiles.active].yaml, for example: userservice-dev.yaml

  • [spring.application.name].yaml, for example: userservice.yaml

It does not[spring.application.name].yaml contain the environment, so it can be shared by multiple environments.

Below we use a case to test configuration sharing

1) Add an environment shared configuration

We add a userservice.yaml file in nacos:
Insert image description here

2) Read the shared configuration in user-service

In the user-service service, modify the PatternProperties class and read the newly added properties:
Insert image description here

In the user-service service, modify the UserController and add a method:
Insert image description here

3) Run two UserApplications, using different profiles

Modify the startup item UserApplication2 and change its profile value:
Insert image description here
Insert image description here

In this way, the profile used by UserApplication (8081) is dev, and the profile used by UserApplication2 (8082) is test.

Start UserApplication and UserApplication2

Visit http://localhost:8081/user/prop, the result is:
Insert image description here

Visit http://localhost:8082/user/prop, the result is:
Insert image description here

It can be seen that both the dev and test environments have read the value of the envSharedValue attribute.

4) Configure the priority of sharing

When the same attribute appears in nacos and service local at the same time, the priority is divided into high and low:

1.4. Build Nacos cluster

In the Nacos production environment, it must be deployed in a cluster state. For the deployment method, please refer to the documents in the pre-course materials:
Insert image description here

2.Feign remote call

Let’s first look at the code we used to use RestTemplate to initiate remote calls:
Insert image description here

The following problems exist:

•Poor code readability and inconsistent programming experience

•URLs with complex parameters are difficult to maintain

Feign is a declarative http client, official address : https://github.com/OpenFeign/feign

Its function is to help us elegantly implement the sending of http requests and solve the problems mentioned above.
Insert image description here

2.1.Feign replaces RestTemplate

The steps to use Fegin are as follows:

1) Introduce dependencies

We introduce the feign dependency in the pom file of the order-service service:

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

2) Add annotations

Add annotations to the startup class of order-service to enable Feign's function:

Insert image description here

3) Write Feign client

Create a new interface in order-service with the following content:

package cn.itcast.order.client;

import cn.itcast.order.pojo.User;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;

@FeignClient("userservice")
public interface UserClient {
    
    
    @GetMapping("/user/{id}")
    User findById(@PathVariable("id") Long id);
}

This client is mainly based on SpringMVC annotations to declare remote call information, such as:

  • Service name: userservice
  • Request method: GET
  • Request path:/user/{id}
  • Request parameters: Long id
  • Return value type: User

In this way, Feign can help us send http requests without using RestTemplate ourselves.

4) Test

Modify the queryOrderById method in the OrderService class in order-service and use Feign client instead of RestTemplate:
Insert image description here

Doesn't it look more elegant?

5) Summary

Steps to use Feign:

①Introduce dependencies

② Add @EnableFeignClients annotation

③ Write FeignClient interface

④ Use the methods defined in FeignClient instead of RestTemplate

2.2. Custom configuration

Feign can support many custom configurations, as shown in the following table:

type effect illustrate
feign.Logger.Level Modify log level Contains four different levels: NONE, BASIC, HEADERS, FULL
feign.codec.Decoder parser for response results Parse the results of http remote calls, such as parsing json strings into java objects
feign.codec.Encoder Request parameter encoding Encode request parameters for easy sending via http request
feign. Contract Supported annotation formats The default is SpringMVC annotation
feign. Retryer Failure retry mechanism Retry mechanism for failed requests. The default is none, but Ribbon's retry will be used.

Under normal circumstances, the default value is sufficient for our use. If you want to customize it, you only need to create a custom @Bean to override the default Bean.

The following uses logs as an example to demonstrate how to customize the configuration.

2.2.1.Configuration file method

Modifying the log level of feign based on the configuration file can target a single service:

feign:  
  client:
    config: 
      userservice: # 针对某个微服务的配置
        loggerLevel: FULL #  日志级别 

Or for all services:

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

There are four levels of logs:

  • NONE: Do not record any log information, this is the default value.
  • BASIC: Only record the requested method, URL, and response status code and execution time
  • HEADERS: Based on BASIC, additional header information of requests and responses is recorded.
  • FULL: Record the details of all requests and responses, including header information, request body, and metadata.

2.2.2.Java code method

You can also modify the log level based on Java code. First declare a class and then declare a Logger.Level object:

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

If you want it to take effect globally , put it in the @EnableFeignClients annotation of the startup class:

@EnableFeignClients(defaultConfiguration = DefaultFeignConfiguration .class) 

If it takes effect locally , put it in the corresponding @FeignClient annotation:

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

2.3.Feign usage optimization

The bottom layer of Feign initiates http requests and relies on other frameworks. Its underlying client implementation includes:

  • URLConnection: Default implementation, does not support connection pooling

  • Apache HttpClient: supports connection pooling

  • OKHttp: supports connection pooling

Therefore, the main way to improve Feign's performance is to use a connection pool instead of the default one URLConnection.

Here we use it Apachefor HttpClientdemonstration.

1) Introduce dependencies

Introduce Apache's HttpClient dependency into the pom file of order-service:

<!--httpClient的依赖 -->
<dependency>
    <groupId>io.github.openfeign</groupId>
    <artifactId>feign-httpclient</artifactId>
</dependency>

2) Configure the connection pool

Add configuration in application.yml of order-service:

feign:
  client:
    config:
      default: # default全局的配置
        loggerLevel: BASIC # 日志级别,BASIC就是基本的请求和响应信息
  httpclient:
    enabled: true # 开启feign对HttpClient的支持
    max-connections: 200 # 最大的连接数
    max-connections-per-route: 50 # 每个路径的最大连接数

Next, break the point in the method FeignClientFactoryBean:loadBalance
Insert image description here

Start the order-service service in Debug mode. You can see the client here. The bottom layer is Apache HttpClient:
Insert image description here

Summary, Feign’s optimization:

1. Try to use basic log level

2. Use HttpClient or OKHttp instead of URLConnection

  • ① Introduce feign-httpClient dependency

  • ② Turn on the httpClient function in the configuration file and set the connection pool parameters

2.4. Best Practices

The so-called recent practice refers to the experience summarized during use, which is the best way to use it.

From self-study observation, we can find that Feign's client and service provider's controller code are very similar:

feign client:
Insert image description here

UserController:
Insert image description here
Is there a way to simplify this repetitive code writing?

2.4.1.Inheritance method

Identical code can be shared through inheritance:

1) Define an API interface, use the definition method, and make declarations based on SpringMVC annotations.

2) Feign client and Controller both integrate modified interfaces
Insert image description here

advantage:

  • Simple
  • Enabled code sharing

shortcoming:

  • Service providers and service consumers are tightly coupled

  • The annotation mapping in the parameter list will not be inherited, so the method, parameter list, and annotations must be declared again in the Controller.

2.4.2. Extraction method

Extract Feign's Client into an independent module, and put the POJO related to the interface and the default Feign configuration into this module for use by all consumers.

For example, the default configurations of UserClient, User, and Feign are extracted into a feign-api package, and all microservices reference this dependency package and can be used directly.
Insert image description here

2.4.3. Implement extraction-based best practices

1) Extraction

First create a module named feign-api:
Insert image description here

Project structure:
Insert image description here

Then introduce feign's starter dependency in feign-api

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

Then, the UserClient, User, and DefaultFeignConfiguration written in order-service are copied to the feign-api project.
Insert image description here

2) Use feign-api in order-service

First, delete the UserClient, User, DefaultFeignConfiguration and other classes or interfaces in order-service.

Introduce the dependency of feign-api into the pom file of order-service:

<dependency>
    <groupId>cn.itcast.demo</groupId>
    <artifactId>feign-api</artifactId>
    <version>1.0</version>
</dependency>

Modify all the import packages related to the above three components in order-service and change them to import the packages in feign-api.

3) Restart the test

After restarting, I found that the service reported an error:
Insert image description here

This is because UserClient is now under the cn.itcast.feign.clients package,

The @EnableFeignClients annotation of order-service is under the cn.itcast.order package. It is not in the same package and cannot scan the UserClient.

4) Solve the scanning package problem

method one:

Specify which packages Feign should scan:

@EnableFeignClients(basePackages = "cn.itcast.feign.clients")

Method two:

Specify the Client interface that needs to be loaded:

@EnableFeignClients(clients = {
    
    UserClient.class})

3.Gateway service gateway

Spring Cloud Gateway is a new project of Spring Cloud. This project is a gateway developed based on reactive programming and event streaming technologies such as Spring 5.0, Spring Boot 2.0 and Project Reactor. It aims to provide a simple and effective unification for microservice architecture. API routing management method.

3.1. Why do we need a gateway?

Gateway Gateway is the gatekeeper of our services and the unified entrance for all microservices.

Core functional features of the gateway :

  • Request routing
  • Permission control
  • Limiting

Architecture diagram:
Insert image description here

Permission control : As the entrance to microservices, the gateway needs to verify whether the user is qualified to request, and if not, intercept it.

Routing and load balancing : All requests must first go through the gateway, but the gateway does not process business, but forwards the request to a certain microservice according to certain rules. This process is called routing. Of course, when there are multiple target services for routing, load balancing is also required.

Current limiting : When the request traffic is too high, the gateway will release the request at the speed that the downstream microservices can accept to avoid excessive service pressure.

There are two types of gateway implementations in Spring Cloud:

  • gateway
  • zul

Zuul is a Servlet-based implementation and belongs to blocking programming. Spring Cloud Gateway is based on WebFlux provided in Spring 5, which is an implementation of reactive programming and has better performance.

3.2.gateway quick start

Next, we will demonstrate the basic routing function of the gateway. The basic steps are as follows:

  1. Create a SpringBoot project gateway and introduce gateway dependencies
  2. Write startup class
  3. Write basic configuration and routing rules
  4. Start the gateway service for testing

1) Create gateway service and introduce dependencies

Create service:
Insert image description here

Introduce dependencies:

<!--网关-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<!--nacos服务发现依赖-->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>

2) Write startup class

package cn.itcast.gateway;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class GatewayApplication {
    
    

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

3) Write basic configuration and routing rules

Create application.yml file with the following content:

server:
  port: 10010 # 网关端口
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/开头就符合要求

We will Pathproxy all requests that meet the rules to urithe address specified by the parameter.

In this example, we proxy /user/**the initial request to lb://userservicelb which is load balancing, and pulls the service list based on the service name to achieve load balancing.

4) Restart the test

Restart the gateway and access http://localhost:10010/user/1, which complies with /user/**the rules. The request is forwarded to uri: http://userservice/user/1, and the result is obtained:
Insert image description here

5) Flow chart of gateway routing

The entire visit process is as follows:
Insert image description here

Summarize:

Gateway construction steps:

  1. Create a project and introduce nacos service discovery and gateway dependencies

  2. Configure application.yml, including basic service information, nacos address, and routing

Routing configuration includes:

  1. Route id: the unique identifier of the route

  2. Routing target (uri): the target address of the route, http represents a fixed address, and lb represents load balancing based on the service name

  3. Routing assertions (predicates): rules for determining routing,

  4. Routing filters: Process requests or responses

Next, focus on learning the detailed knowledge of routing assertions and routing filters.

3.3. Assertion factory

The assertion rules we wrote in the configuration file are just strings. These strings will be read and processed by the Predicate Factory and turned into conditions for routing judgments.

For example, Path=/user/** is matched according to the path. This rule is composed of

org.springframework.cloud.gateway.handler.predicate.PathRoutePredicateFactoryClass comes

For processing, there are more than a dozen assertion factories like this one in SpringCloudGateway:

name illustrate Example
After It is a request after a certain point in time - After=2037-01-20T17:42:47.789-07:00[America/Denver]
Before It is a request before a certain point in time - Before=2031-04-13T15:14:47.433+08:00[Asia/Shanghai]
Between It is a request before a certain two points in time. - Between=2037-01-20T17:42:47.789-07:00[America/Denver], 2037-01-21T17:42:47.789-07:00[America/Denver]
Cookie The request must contain certain cookies - Cookie=chocolate, ch.p
Header The request must contain certain headers - Header=X-Request-Id, \d+
Host The request must be to access a certain host (domain name) - Host=.somehost.org,.anotherhost.org
Method The request method must be the specified method - Method=GET,POST
Path The request path must comply with the specified rules - Path=/red/{segment},/blue/**
Query The request parameters must contain the specified parameters - Query=name, Jack or - Query=name
RemoteAddr The requester's IP must be in the specified range - RemoteAddr=192.168.1.1/24
Weight Weight processing

We only need to master the routing engineering of Path.

3.4. Filter factory

GatewayFilter is a filter provided in the gateway, which can process requests entering the gateway and responses returned by microservices:
Insert image description here

3.4.1. Types of routing filters

Spring provides 31 different route filter factories. For example:

name illustrate
AddRequestHeader Add a request header to the current request
RemoveRequestHeader Remove a request header from the request
AddResponseHeader Add a response header to the response result
RemoveResponseHeader Removes a response header from the response result
RequestRateLimiter Limit requested traffic

3.4.2. Request header filter

Let's take AddRequestHeader as an example to explain.

Requirement : Add a request header to all requests entering userservice: Truth=itcast is freaking awesome!

You only need to modify the application.yml file of the gateway service and add route filtering:

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

The current filter is written under the userservice route, so it is only effective for requests to access userservice.

3.4.3.Default filter

If you want it to be effective for all routes, you can write the filter factory to default. The format is as follows:

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

3.4.4. Summary

What does the filter do?

① Process the routing request or response, such as adding request headers

② The filters configured under routing only take effect on requests for the current route.

What is the role of defaultFilters?

① Filter that takes effect on all routes

3.5.Global filters

The gateway provides 31 types of filters learned in the previous section, but the function of each filter is fixed. If we want to intercept requests, we can't do it by doing our own business logic.

3.5.1. Global filter function

The role of the global filter is also to process all requests and microservice responses entering the gateway, which is the same as the role of GatewayFilter. The difference is that GatewayFilter is defined through configuration and the processing logic is fixed; while the logic of GlobalFilter needs to be written and implemented by yourself.

The definition is to implement the GlobalFilter interface.

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

Writing custom logic in filter can achieve the following functions:

  • Login status judgment
  • Permission verification
  • Request current limit, etc.

3.5.2. Customize global filters

Requirements: Define global filters, intercept requests, and determine whether the request parameters meet the following conditions:

  • Whether there is authorization in the parameters?

  • Whether the authorization parameter value is admin

If both are satisfied, release, otherwise intercept

accomplish:

Define a filter in the gateway:

package cn.itcast.gateway.filters;

import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

@Order(-1)
@Component
public class AuthorizeFilter implements GlobalFilter {
    
    
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
    
    
        // 1.获取请求参数
        MultiValueMap<String, String> params = exchange.getRequest().getQueryParams();
        // 2.获取authorization参数
        String auth = params.getFirst("authorization");
        // 3.校验
        if ("admin".equals(auth)) {
    
    
            // 放行
            return chain.filter(exchange);
        }
        // 4.拦截
        // 4.1.禁止访问,设置状态码
        exchange.getResponse().setStatusCode(HttpStatus.FORBIDDEN);
        // 4.2.结束处理
        return exchange.getResponse().setComplete();
    }
}

3.5.3. Filter execution order

Requests entering the gateway will encounter three types of filters: current route filters, DefaultFilter, and GlobalFilter

After requesting routing, the current routing filter, DefaultFilter, and GlobalFilter will be merged into a filter chain (set), and each filter will be executed in sequence after sorting:

Insert image description here

What are the rules for sorting?

  • Each filter must specify an order value of type int. The smaller the order value, the higher the priority and the higher the execution order .
  • GlobalFilter specifies the order value by implementing the Ordered interface or adding the @Order annotation, which we specify ourselves.
  • The order of routing filters and defaultFilter is specified by Spring, and the default is to increase from 1 in the order of declaration.
  • When the order values ​​of the filters are the same, they will be executed in the order of defaultFilter > routing filter > GlobalFilter.

For details, you can view the source code:

org.springframework.cloud.gateway.route.RouteDefinitionRouteLocator#getFilters()The method is to load the defaultFilters first, then load the filters of a certain route, and then merge them.

org.springframework.cloud.gateway.handler.FilteringWebHandler#handle()The method will load the global filter, merge it with the previous filter, sort it according to order, and organize the filter chain.

3.6. Cross-domain issues

3.6.1. What are cross-domain issues?

Cross-domain: If the domain name is inconsistent, it means cross-domain, which mainly includes:

  • Different domain names: www.taobao.com and www.taobao.org and www.jd.com and miaosha.jd.com

  • The domain name is the same but the ports are different: localhost:8080 and localhost8081

Cross-domain problem: The browser prohibits cross-domain ajax requests between the request initiator and the server, and the request is intercepted by the browser.

Solution: CORS, you should have learned this before, so I won’t go into details here. Friends who don’t know can check it out

3.6.2. Simulate cross-domain issues

Find the page file of the pre-class materials:
Insert image description here

Put it into a web server such as tomcat or nginx, start it and access it.

You can see the following error in the browser console:
Insert image description here

Accessing localhost:10010 from localhost:8090 has different ports, which is obviously a cross-domain request.

3.6.3. Solving cross-domain issues

In the application.yml file of the gateway service, add the following configuration:

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 # 这次跨域检测的有效期

Guess you like

Origin blog.csdn.net/CSDN_Admin0/article/details/131918433