中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

如何對HttpServletRequest中的Header進行增刪

發布時間:2021-10-11 17:20:21 來源:億速云 閱讀:262 作者:iii 欄目:編程語言

這篇文章主要講解了“如何對HttpServletRequest中的Header進行增刪”,文中的講解內容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“如何對HttpServletRequest中的Header進行增刪”吧!

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

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

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 只是一個接口,實現由Servlet容器提供。不管是任何容器,實現類,肯定是要把請求的Header存儲在某個地方,于是可以通過反射來對存儲Header的容器進行增刪。

先定義一個測試的Controller

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

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,響應給客戶端。 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的實現

Tomcat使用了外觀模式(Facade),這個實現稍微有一點點復雜

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 實現,它有一個org.apache.catalina.connector.Request 的對象。這個對象又有一個org.apache.coyote.Request的對象,這個對象又有一個org.apache.tomcat.util.http.MimeHeaders 字段,它就是存儲了客戶端請求頭的容器,只要通過反射獲取到這個MimeHeaders,對它進行修改即可。

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進行增刪

假設的場景是,需要對請求Header統一添加一個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,隨機生成請求ID
		mimeHeaders.addValue("x-request-id").setString(UUID.randomUUID().toString());;
		// 移除一個header
		mimeHeaders.removeHeader("User-Agent");
	}
}

請求Controller獲取響應結果

如何對HttpServletRequest中的Header進行增刪 可以看到成功添加了x-request-id header,并且刪除了User-Agent header。

SpringBoot默認的Servlet容器就是Tomcat

使用Undertow作為容器

越來越多人使用Undertow作為Servlet容器,據說性能比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實現

它的實現就比較簡單

io.undertow.servlet.spec.HttpServletRequestImpl
|-io.undertow.server.HttpServerExchange
  |-io.undertow.util.HeaderMap

io.undertow.servlet.spec.HttpServletRequestImpl實現類中有一個屬性對象io.undertow.server.HttpServerExchange,這個屬性對象又包含了一個io.undertow.util.HeaderMapHeaderMap就是請求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進行增刪

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獲取結果

如何對HttpServletRequest中的Header進行增刪

感謝各位的閱讀,以上就是“如何對HttpServletRequest中的Header進行增刪”的內容了,經過本文的學習后,相信大家對如何對HttpServletRequest中的Header進行增刪這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關知識點的文章,歡迎關注!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

香河县| 东方市| 长白| 乐都县| 钦州市| 杨浦区| 洛浦县| 汝南县| 波密县| 莱西市| 两当县| 和平区| 东乡县| 咸阳市| 新建县| 定陶县| 五华县| 淳化县| 基隆市| 琼结县| 余姚市| 南康市| 石门县| 利辛县| 兰溪市| 道真| 札达县| 宜川县| 柞水县| 海门市| 赤城县| 朔州市| 玉树县| 红安县| 博罗县| 廊坊市| 雅安市| 山阴县| 石狮市| 华阴市| 北票市|