Spring中如何拿到request

比如我在service层方法中想要拿到request对象,可以通过controller层来传递,这是一种方法,还有就是RequestContextHolder:

/**
 * Holder class to expose the web request in the form of a thread-bound
 * {@link RequestAttributes} object. The request will be inherited
 * by any child threads spawned by the current thread if the
 * {@code inheritable} flag is set to {@code true}.
 *

翻译过来是通过线程绑定的方式暴露request对象,如果将Inheritable标志设置为true,则当前线程产生的任何子线程都将继承该请求。
既要绑定request对象到线程,又要有继承性的限制,可以想到threadlocal,并且RequestContextHolder也是这么实现的:

	public static void setRequestAttributes(RequestAttributes attributes, boolean inheritable) {
		if (attributes == null) {
			resetRequestAttributes();
		}
		else {
			<-- 默认是false -->
			if (inheritable) {
				inheritableRequestAttributesHolder.set(attributes);
				requestAttributesHolder.remove();
			}
			else {
				requestAttributesHolder.set(attributes);
				inheritableRequestAttributesHolder.remove();
			}
		}
	}

其中定义了两个threadLocal:

	private static final ThreadLocal<RequestAttributes> requestAttributesHolder =
			new NamedThreadLocal<RequestAttributes>("Request attributes");

	private static final ThreadLocal<RequestAttributes> inheritableRequestAttributesHolder =
			new NamedInheritableThreadLocal<RequestAttributes>("Request context");

后者用在如果要在当前线程创建子线程并且还要继承当前线程中的变量的场景。
然后就可以通过如下方式拿到request了:

        HttpServletRequest request = ((ServletRequestAttributes) (RequestContextHolder.currentRequestAttributes())).getRequest();
        Enumeration<String> names = request.getServletContext().getAttributeNames();
        while (names.hasMoreElements()) {
            System.out.println(names.nextElement());
        }

那ThreadLocal是怎么保证不同线程中变量互不影响呢:

    public void set(T value) {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
    }
    ThreadLocalMap getMap(Thread t) {
        return t.threadLocals;
    }
    /* ThreadLocal values pertaining to this thread. This map is maintained
     * by the ThreadLocal class. */
    ThreadLocal.ThreadLocalMap threadLocals = null;

注意:ThreadLocal不存东西,它只是作为key放入ThreadLocalMap里,然后 每个线程都有一个类型为ThreadLocalMap的threadLocals属性
RequestContextHolder就能拿到每个线程的不同的request了

Spring Cloud Gateway中,要获取request body可以通过自定义过滤器来实现。下面我将为您提供一个示例来演示如何获取request body。 首先,您需要创建一个自定义的GlobalFilter,该过滤器将在请求被路由之前执行。在该过滤器内部,您可以使用ServerWebExchange对象来获取request body。 ```java @Component public class RequestBodyFilter implements GlobalFilter { @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { // 获取请求体 return DataBufferUtils.join(exchange.getRequest().getBody()) .flatMap(dataBuffer -> { // 读取请求体数据 byte[] bytes = new byte[dataBuffer.readableByteCount()]; dataBuffer.read(bytes); // 将字节数组转换为字符串 String requestBody = new String(bytes, StandardCharsets.UTF_8); // 在这里可以进行对请求体的处理,比如记录日志、验签等操作 // ... // 打印请求体 System.out.println("Request Body: " + requestBody); // 继续执行后续过滤器和路由操作 return chain.filter(exchange); }); } } ``` 通过以上代码,您可以在filter方法中获取request body数据,并进行相应的处理。例如,您可以在这里记录日志、验证签名等操作。在示例中,我们只是简单地打印了request body。 注意,上述示例中的自定义过滤器需要添加@Component注解,并且Spring Boot应用需要开启@EnableDiscoveryClient注解。 希望以上信息对您有所帮助!如有任何疑问,请随时向我提问。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值