Implementation of transparent transmission of microservice parameters

Note: In the microservice architecture, after the user identity is verified by the gateway, we can add user information, such as ID, to the request header . In the subsequent microservices, you can set up an interceptor to intercept the request, obtain the user ID in the request header , and add it to ThreadLocal.

The most important thing is that when the current microservice initiates a request and calls other microservices, the outgoing request needs to be intercepted and the user ID in the local thread pool is put into the request header again, thus realizing user information . The flow in microservices is called parameter transparent transmission. This article introduces the implementation of transparent transmission of the above parameters.

Insert image description here

In a microservice system, there is generally a common module that is commonly referenced by all microservices. For example, the module is named Base, Util, Feign-API. We can write the interceptor for parameter transparent transmission in this module, so There is no need to write interceptor configuration classes for other microservices.

For example, in my current system, the Feign-API module is commonly referenced by all microservices. Some common DTO objects and Feign-Client class objects are written in it;

Insert image description here

accomplish

Step 1: Create the ThreadLocal class

In the FeignAPI module, create a local thread pool object to store the current user's ID;

/**
 * 本地线程池
 */
public class TokenThreadLocal {
    
    
    
    private static final ThreadLocal<Long> THREAD_LOCAL= new ThreadLocal<>();

    /**
     * 设置
     * @param tokenId
     */
    public static void set(Long tokenId){
    
    
        THREAD_LOCAL.set(tokenId);
    }

    /**
     * 获取
     * @return
     */
    public static Long get(){
    
    
        return THREAD_LOCAL.get();
    }

    /**
     * 移除
     */
    public static void remove(){
    
    
        THREAD_LOCAL.remove();
    }
}

Step 2: Create MVC interceptor

In the FeignAPI module, create an MVC interceptor (HandlerInterceptor), and the interception path is all paths;

package com.hzy.interceptor;

import com.hzy.config.TokenThreadLocal;
import org.springframework.http.HttpStatus;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * 接收请求拦截器
 */
public class AuthorizationInterceptor implements HandlerInterceptor {
    
    

    /**
     * 收到请求会执行的方法
     * @param request
     * @param response
     * @param handler
     * @return
     * @throws Exception
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    
    
        
        // 获取请求头中的用户ID
        String id = request.getHeader("authorization");

        // 判断用户ID是否为空
        if (id != null && id != ""){
    
    
            // 将字符串转换为Long类型
            long l = Long.parseLong(id);
            
            // 将用户ID存入ThreadLocal中
            TokenThreadLocal.set(l);
        }else {
    
    
            responseHandler(response);
            return false;
        }

        // 放行
        return true;
    }

    /**
     * 请求返回客户端之前会执行的方法
     * @param request
     * @param response
     * @param handler
     * @param modelAndView
     * @throws Exception
     */
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
    
    
        HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
    }

    /**
     * 请求到客户端之后会执行的方法
     * @param request
     * @param response
     * @param handler
     * @param ex
     * @throws Exception
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
    
    
        TokenThreadLocal.remove();
    }

    /**
     * 用户尚未登录的返回信息
     * @param response
     * @return
     * @throws IOException
     */
    private boolean responseHandler(HttpServletResponse response) throws IOException {
    
    
        // 设置响应状态码 401 如果用户未登录 状态码都返回401
        response.setStatus(HttpStatus.UNAUTHORIZED.value());

        // 响应的数据类型和编码格式
        response.setContentType("application/json;charset=UTF-8");

        // 提示信息
        response.getWriter().write("用户未登录");

        return false;
    }
}

Interceptor configuration class, set to intercept all path requests;

import com.hzy.interceptor.AuthorizationInterceptor;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

/**
 * 接收请求拦截器配置类
 */
public class MVCInterceptorConfig implements WebMvcConfigurer {
    
    

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
    
    
        registry.addInterceptor(new AuthorizationInterceptor())
                .addPathPatterns("/**");
    }
}

Step 3: Create Feign interceptor

Create Feign's interceptor (RequestInterceptor), which is used to intercept requests sent by the current microservice. The code content is to put the user ID of the current local thread pool into the request header again and pass it to the downstream microservice for analysis;

import com.hzy.config.TokenThreadLocal;
import feign.RequestInterceptor;
import feign.RequestTemplate;

/**
 * 发送请求拦截器
 */
public class AuthorizationRequestInterceptor implements RequestInterceptor {
    
    

    @Override
    public void apply(RequestTemplate requestTemplate) {
    
    
        // 从本地线程池中获取用户ID,放入请求头中
        requestTemplate.header("authorization",TokenThreadLocal.get().toString());
    }
}

test

Test the order service. When generating an order, the inventory service will be called to query inventory information. Break points in the MVC, Feign interceptor, and call inventory service lines respectively, send requests, and view the execution process;

Insert image description here

The request passes through the gateway and is first intercepted by the MCV interceptor of the order service. You can see that the current user's ID is 2 and is allowed...

Insert image description here

Then, the breakpoint comes to the order service, call the inventory service, release it, and check whether the outgoing request will be intercepted;

Insert image description here

The breakpoint is blocked by the Feign interceptor (RequestInterceptor), the parameters are put into the request header, and then released...

Insert image description here

The request comes to the MVC interceptor again. Note that this is not the order service, but the inventory service interceptor;

itemId

In this way, the flow of user parameters in the microservice system is realized.

Summarize

Use two interceptors, one in front and one behind, to intercept the microservice before accepting the request and before sending the request to achieve transparent transmission of parameters. But you need to pay attention to the following two points:

  • The two interceptors rely on the local thread pool, so if the microservice sends an asynchronous message (such as MQ), it will not work (reference: http://t.csdn.cn/wWsb7 );

  • The interceptor is written in the common module, so the prerequisite for parameters to be transferred is that the current microservice references the common module ;

Guess you like

Origin blog.csdn.net/qq_42108331/article/details/132293110