最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

對HttpServletRequest中的Header進(jìn)行增刪實現(xiàn)過程

 更新時間:2025年12月18日 10:59:36   作者:_派大星  
文章介紹了如何通過反射來修改和刪除HttpServletRequest中的Header,以實現(xiàn)對外部請求數(shù)據(jù)的自定義處理,通過示例代碼和分析,展示了如何在Tomcat和Undertow容器中實現(xiàn)這一功能

HttpServletRequest 沒有提供修改/刪除的 Api

HttpServletRequest中定義的對 Header 的操作全是只讀,沒有修改。

代碼實現(xiàn)如下:

public interface HttpServletRequest extends ServletRequest {
    ...
    public long getDateHeader(String name);
    public String getHeader(String name);
    public Enumeration<String> getHeaders(String name);
    public Enumeration<String> getHeaderNames();
    public int getIntHeader(String name);
    ...
}

HttpServletRequest 只是一個接口,實現(xiàn)由 Servlet 容器提供。

不管是任何容器,實現(xiàn)類,肯定是要把請求的 Header 存儲在某個地方,于是可以通過反射來對存儲Header的容器進(jìn)行增刪。

先定義一個測試的 Controller

這個 Controller 很簡單,把客戶端的所有 Header,以 JSON 形似響應(yīng)給客戶端。

import java.util.ArrayList;
import java.util.Enumeration;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/demo")
public class DemoController {

	// 遍歷所有請求Header,響應(yīng)給客戶端。 map<string, string[]>
	@GetMapping
	public Object demo (HttpServletRequest request) {
		Map<String, List<String>> headers = new LinkedHashMap<>();
		Enumeration<String> nameEnumeration = request.getHeaderNames();
		while (nameEnumeration.hasMoreElements()) {
			String name = nameEnumeration.nextElement();
			List<String> values = headers.get(name);
			if (values == null) {
				values = new ArrayList<>();
				headers.put(name, values);
			}
			Enumeration<String> valueEnumeration = request.getHeaders(name);
			while (valueEnumeration.hasMoreElements()) {
				values.add(valueEnumeration.nextElement());
			}
		}
		return headers;
	}
}

使用 Tomcat 作為容器

Tomcat 對 HttpServletRequest 的實現(xiàn)

Tomcat 使用了外觀模式(Facade),這個實現(xiàn)稍微有一點(diǎn)點(diǎn)復(fù)雜

org.apache.catalina.connector.RequestFacade
|-org.apache.catalina.connector.Request
  |-org.apache.coyote.Request
    |-org.apache.tomcat.util.http.MimeHeaders

首先是 org.apache.catalina.connector.RequestFacade 實現(xiàn),它有一個org.apache.catalina.connector.Request 的對象。

這個對象又有一個org.apache.coyote.Request的對象,這個對象又有一個org.apache.tomcat.util.http.MimeHeaders 字段,它就是存儲了客戶端請求頭的容器,只要通過反射獲取到這個MimeHeaders,對它進(jìn)行修改即可。

org.apache.catalina.connector.RequestFacade

public class RequestFacade implements HttpServletRequest {
    protected org.apache.catalina.connector.Request request = null;
    ...
}

org.apache.catalina.connector.Request

public class Request implements HttpServletRequest {
    protected org.apache.coyote.Request coyoteRequest;
    ...
}

org.apache.coyote.Request coyoteRequest

public final class Request {
    private final org.apache.tomcat.util.http.MimeHeaders headers = new MimeHeaders();
}

在 Filter 中通過反射對請求 Header 進(jìn)行增刪

假設(shè)的場景是,需要對請求 Header 統(tǒng)一添加一個x-request-id,通過這個 ID 來從日志中定位每一個請求。

import java.io.IOException;
import java.lang.reflect.Field;
import java.util.UUID;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.catalina.connector.Request;
import org.apache.catalina.connector.RequestFacade;
import org.apache.tomcat.util.http.MimeHeaders;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.util.ReflectionUtils;



@WebFilter(urlPatterns = "/*")
@Component
@Order(-999)
public class RequestIdGenFilter extends HttpFilter {

	/**
	 *
	 */
	private static final long serialVersionUID = 1787347739651657706L;

	@Override
	protected void doFilter(HttpServletRequest req, HttpServletResponse res, FilterChain chain) throws IOException, ServletException {
		try {
			// 從 RequestFacade 中獲取 org.apache.catalina.connector.Request
			Field connectorField = ReflectionUtils.findField(RequestFacade.class, "request", Request.class);
			connectorField.setAccessible(true);
			Request connectorRequest = (Request) connectorField.get(req);

			// 從 org.apache.catalina.connector.Request 中獲取 org.apache.coyote.Request
			Field coyoteField = ReflectionUtils.findField(Request.class, "coyoteRequest", org.apache.coyote.Request.class);
			coyoteField.setAccessible(true);
			org.apache.coyote.Request coyoteRequest = (org.apache.coyote.Request) coyoteField.get(connectorRequest);

			// 從 org.apache.coyote.Request 中獲取 MimeHeaders
			Field mimeHeadersField =  ReflectionUtils.findField(org.apache.coyote.Request.class, "headers", MimeHeaders.class);
			mimeHeadersField.setAccessible(true);
			MimeHeaders mimeHeaders =  (MimeHeaders) mimeHeadersField.get(coyoteRequest);

			this.mineHeadersHandle(mimeHeaders);
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
		super.doFilter(req, res, chain);
	}

	protected void mineHeadersHandle (MimeHeaders mimeHeaders) {
		// 添加一個Header,隨機(jī)生成請求ID
		mimeHeaders.addValue("x-request-id").setString(UUID.randomUUID().toString());;
		// 移除一個header
		mimeHeaders.removeHeader("User-Agent");
	}
}

請求 Controller 獲取響應(yīng)結(jié)果

可以看到成功添加了x-request-id header,并且刪除了User-Agent header。

使用 Undertow 作為容器

越來越多人使用 Undertow 作為 Servlet 容器,據(jù)說性能比 Tomcat 要好很多

SpringBoot 替換 Tomcat 為 Undertow

只需要把spring-boot-starter-web中的spring-boot-starter-tomcat排除,然后手動添加spring-boot-starter-undertow即可

<dependencies>
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    <exclusions>
      <exclusion>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-tomcat</artifactId>
      </exclusion>
    </exclusions>
  </dependency>
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-undertow</artifactId>
  </dependency>
</dependencies>

Undertow 中的HttpServletRequest實現(xiàn)

它的實現(xiàn)就比較簡單,結(jié)構(gòu)如下:

io.undertow.servlet.spec.HttpServletRequestImpl
|-io.undertow.server.HttpServerExchange
  |-io.undertow.util.HeaderMap
  • io.undertow.servlet.spec.HttpServletRequestImpl實現(xiàn)類中有一個屬性對象
  • io.undertow.server.HttpServerExchange,這個屬性對象又包含了一個io.undertow.util.HeaderMap,HeaderMap就是請求 Header 的存儲容器,反射獲取它就行。

io.undertow.servlet.spec.HttpServletRequestImpl

public final class HttpServletRequestImpl implements HttpServletRequest {
    private final io.undertow.server.HttpServerExchange exchange;
}

io.undertow.server.HttpServerExchange

public final class HttpServerExchange extends AbstractAttachable {
    private final HeaderMap requestHeaders;
}

在 Filter 中通過反射對請求 Header 進(jìn)行增刪

import java.io.IOException;
import java.lang.reflect.Field;
import java.util.UUID;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.util.ReflectionUtils;

import io.undertow.server.HttpServerExchange;
import io.undertow.servlet.spec.HttpServletRequestImpl;
import io.undertow.util.HeaderMap;
import io.undertow.util.HttpString;



@WebFilter(urlPatterns = "/*")
@Component
@Order(-999)
public class RequestIdGenFilter extends HttpFilter {

	/**
	 *
	 */
	private static final long serialVersionUID = 1787347739651657706L;

	@Override
	protected void doFilter(HttpServletRequest req, HttpServletResponse res, FilterChain chain) throws IOException, ServletException {
		try {
			// 從HttpServletRequestImpl中獲取HttpServerExchange
			Field exchangeField = ReflectionUtils.findField(HttpServletRequestImpl.class, "exchange", HttpServerExchange.class);
			exchangeField.setAccessible(true);
			HttpServerExchange httpServerExchange = (HttpServerExchange) exchangeField.get(req);

			// 從HttpServerExchange中獲取HeaderMap
			Field headerMapField = ReflectionUtils.findField(HttpServerExchange.class, "requestHeaders", HeaderMap.class);
			headerMapField.setAccessible(true);

			HeaderMap requestHeaderMap = (HeaderMap) headerMapField.get(httpServerExchange);
			this.handleRequestHeaderMap(requestHeaderMap);
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
		super.doFilter(req, res, chain);
	}

	private void handleRequestHeaderMap(HeaderMap requestHeaderMap) {
		// 添加Header
		requestHeaderMap.add(new HttpString("x-request-id"), UUID.randomUUID().toString());
		// 移除Header
		requestHeaderMap.remove("User-Agent");
	}
}

請求 Controller 獲取結(jié)果

總結(jié)

還有其他的 Servlet 容器,例如 Jetty。只要熟悉基本的反射,實現(xiàn)對請求頭的增刪,都很簡單。

以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • MyBatis與SpringMVC相結(jié)合實現(xiàn)文件上傳、下載功能

    MyBatis與SpringMVC相結(jié)合實現(xiàn)文件上傳、下載功能

    這篇文章主要介紹了MyBatis與SpringMVC相結(jié)合實現(xiàn)文件上傳、下載功能的相關(guān)資料,非常不錯,具有參考借鑒價值,需要的朋友可以參考下
    2016-06-06
  • SpringBoot使用Redis對用戶IP進(jìn)行接口限流的示例詳解

    SpringBoot使用Redis對用戶IP進(jìn)行接口限流的示例詳解

    使用接口限流的主要目的在于提高系統(tǒng)的穩(wěn)定性,防止接口被惡意打擊,這篇文章主要介紹了SpringBoot使用Redis對用戶IP進(jìn)行接口限流的示例代碼,需要的朋友可以參考下
    2023-07-07
  • JAVA通過Filter實現(xiàn)允許服務(wù)跨域請求的方法

    JAVA通過Filter實現(xiàn)允許服務(wù)跨域請求的方法

    這里的域指的是這樣的一個概念:我們認(rèn)為若協(xié)議 + 域名 + 端口號均相同,那么就是同域即我們常說的瀏覽器請求的同源策略。這篇文章主要介紹了JAVA通過Filter實現(xiàn)允許服務(wù)跨域請求,需要的朋友可以參考下
    2018-11-11
  • 淺析如何使用Swagger生成帶權(quán)限控制的API文檔

    淺析如何使用Swagger生成帶權(quán)限控制的API文檔

    當(dāng)涉及到權(quán)限控制時,如何生成既安全又詳細(xì)的?API?文檔就成了一個關(guān)鍵問題,所以這篇文章小編就來和大家好好聊聊如何用?Swagger?來生成帶有權(quán)限控制的?API?文檔吧
    2025-02-02
  • Java 在PDF中添加騎縫章示例解析

    Java 在PDF中添加騎縫章示例解析

    這篇文章主要介紹了Java 在PDF中添加騎縫章示例解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-07-07
  • Spring Boot 配置大全(小結(jié))

    Spring Boot 配置大全(小結(jié))

    本篇文章主要介紹了Spring Boot 配置大全(小結(jié)),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-11-11
  • Java參數(shù)校驗@Validated、@Valid介紹及使用詳解

    Java參數(shù)校驗@Validated、@Valid介紹及使用詳解

    Javax.validation是?spring?集成自帶的一個參數(shù)校驗接口,可通過添加注解來設(shè)置校驗條件,這篇文章主要介紹了Java參數(shù)校驗@Validated、@Valid介紹及使用詳解,需要的朋友可以參考下
    2024-08-08
  • 通過案例了解靜態(tài)修飾符static使用場景

    通過案例了解靜態(tài)修飾符static使用場景

    這篇文章主要介紹了通過案例了解靜態(tài)修飾符static使用場景,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-10-10
  • 性能爆棚的實體轉(zhuǎn)換復(fù)制工具M(jìn)apStruct使用詳解

    性能爆棚的實體轉(zhuǎn)換復(fù)制工具M(jìn)apStruct使用詳解

    這篇文章主要為大家介紹了性能爆棚的實體轉(zhuǎn)換復(fù)制工具M(jìn)apStruct使用詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-03-03
  • SpringBoot自定義動態(tài)數(shù)據(jù)源的流程步驟

    SpringBoot自定義動態(tài)數(shù)據(jù)源的流程步驟

    動態(tài)數(shù)據(jù)源,本質(zhì)上是把多個數(shù)據(jù)源存儲在一個?Map?中,當(dāng)需要使用某一個數(shù)據(jù)源時,使用?key?獲取指定數(shù)據(jù)源進(jìn)行處理,本文將給大家介紹一下SpringBoot自定義動態(tài)數(shù)據(jù)源的流程步驟,需要的朋友可以參考下
    2024-06-06

最新評論

常德市| 中江县| 镇原县| 杭锦后旗| 娄底市| 漯河市| 永修县| 苏尼特左旗| 宜川县| 广南县| 灵台县| 乌鲁木齐县| 新河县| 五家渠市| 泽州县| 丹巴县| 云浮市| 怀来县| 美姑县| 满洲里市| 宜宾市| 大庆市| 志丹县| 富阳市| 黔西县| 佛学| 子洲县| 石首市| 观塘区| 庆安县| 桂平市| 秀山| 巢湖市| 巴中市| 永年县| 崇仁县| 汾阳市| 福鼎市| 孝昌县| 青川县| 南溪县|