request-添加head信息-反射

原理

分析HttpServletRequest对象的数据结构,同时查看源码可知:

  1. HttpServletRequest的实现类RequestFacade中有变量org.apache.catalina.connector.Request request
  2. org.apache.catalina.connector.Request类中有变量org.apache.coyote.Request coyoteRequest
  3. org.apache.coyote.Request中有变量MimeHeaders headers,且提供方法public MimeHeaders getMimeHeaders()
  4. 而MimeHeaders就是head信息的容器,setValue(key).setString(value)即可添加指定head信息
  5. 所以,我们只需要通过反射获取RequestFacade中的org.apache.coyote.Request,再调用getMimeHeadersd得到MimeHeaders即可。

代码

注意class别import错了。

package com.zhilei.common.util.http;

import org.apache.catalina.connector.Request;
import org.apache.catalina.connector.RequestFacade;
import org.apache.tomcat.util.http.MimeHeaders;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Field;

/**
 * @author chenzy
 * @since 2020-11-30
 */
public class RequestUtil {
    private RequestUtil(){}
    
    public static boolean setHead(HttpServletRequest request, String key, String value){
        try {
            Field requestField = RequestFacade.class.getDeclaredField("request");
            requestField.setAccessible(true);
            Request requestReal= (Request) requestField.get(request);

            Field coyoteRequestField =Request.class.getDeclaredField("coyoteRequest");
            coyoteRequestField.setAccessible(true);
            org.apache.coyote.Request coyoteRequest= (org.apache.coyote.Request) coyoteRequestField.get(requestReal);
            MimeHeaders headers= coyoteRequest.getMimeHeaders();
            headers.setValue(key).setString(value);
            return true;
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        return false;
    }
}

		<tomcat.version>9.0.29</tomcat.version>
        <dependency>
            <groupId>org.apache.tomcat.embed</groupId>
            <artifactId>tomcat-embed-core</artifactId>
            <version>${tomcat.version}</version>
        </dependency>

在springboot中的使用

当controller的参数转换错误时,setHead方法异常

  1. 分析:我的setHead方法是在HandlerInterceptor.preHandle中调用,当controller的参数转换错误时,preHandle会执行两次,第一次可以正常setHead,第二次报错,因为HttpServletRequest参数的实际类型是org.apache.catalina.core.ApplicationHttpRequest,此类不是RequestFacade的子类。但是调试发现ApplicationHttpRequest中有属性RequestFacade request,且发现此属性继承于ServletRequestWrapper。所以改进setHead方法。
  2. 代码:
package com.zhilei.common.util.http;

import org.apache.catalina.connector.Request;
import org.apache.catalina.connector.RequestFacade;
import org.apache.tomcat.util.http.MimeHeaders;

import javax.servlet.ServletRequestWrapper;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Field;

/**
 * @author chenzy
 * @since 2020-11-30
 */
public class RequestUtil {
    private RequestUtil() {
    }

    public static boolean setHead(HttpServletRequest request, String key, String value) {
        if (request instanceof RequestFacade) {
            return setHead((RequestFacade) request, key, value);
        } else if (request instanceof ServletRequestWrapper) {
            /*当controller参数转换错误时 request为org.apache.catalina.core.ApplicationHttpRequest,且此类继承ServletRequestWrapper,再次父类有字段request,为RequestFacade实例*/
            return setHead(getRequestFacade(request), key, value);
        }
        return false;

    }
    private static RequestFacade getRequestFacade(HttpServletRequest request) {
        try {
            if (request instanceof ServletRequestWrapper) {
                Field requestField = ServletRequestWrapper.class.getDeclaredField("request");
                requestField.setAccessible(true);
                HttpServletRequest requestTarget = (HttpServletRequest) requestField.get(request);
                if (requestTarget instanceof RequestFacade){
                    return (RequestFacade) requestTarget;
                }
            }
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        return null;
    }

    private static boolean setHead(RequestFacade request, String key, String value) {
        if (request==null){
            return false;
        }
        try {
            Field requestField = RequestFacade.class.getDeclaredField("request");
            requestField.setAccessible(true);
            Request requestReal = (Request) requestField.get(request);

            Field coyoteRequestField = Request.class.getDeclaredField("coyoteRequest");
            coyoteRequestField.setAccessible(true);
            org.apache.coyote.Request coyoteRequest = (org.apache.coyote.Request) coyoteRequestField.get(requestReal);
            MimeHeaders headers = coyoteRequest.getMimeHeaders();
            headers.setValue(key).setString(value);
            return true;
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        return false;
    }
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值