溫馨提示×

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

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

如何對(duì)HttpServletRequest中的Header進(jìn)行增刪

發(fā)布時(shí)間:2021-10-11 17:20:21 來(lái)源:億速云 閱讀:249 作者:iii 欄目:編程語(yǔ)言

這篇文章主要講解了“如何對(duì)HttpServletRequest中的Header進(jìn)行增刪”,文中的講解內(nèi)容簡(jiǎn)單清晰,易于學(xué)習(xí)與理解,下面請(qǐng)大家跟著小編的思路慢慢深入,一起來(lái)研究和學(xué)習(xí)“如何對(duì)HttpServletRequest中的Header進(jìn)行增刪”吧!

HttpServletRequest 沒(méi)有提供修改/刪除的Api

HttpServletRequest中定義的對(duì)Header的操作全是只讀,沒(méi)有修改。

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 只是一個(gè)接口,實(shí)現(xiàn)由Servlet容器提供。不管是任何容器,實(shí)現(xiàn)類(lèi),肯定是要把請(qǐng)求的Header存儲(chǔ)在某個(gè)地方,于是可以通過(guò)反射來(lái)對(duì)存儲(chǔ)Header的容器進(jìn)行增刪。

先定義一個(gè)測(cè)試的Controller

這個(gè)Controller很簡(jiǎn)單,把客戶端的所有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 {
	
	// 遍歷所有請(qǐng)求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對(duì)HttpServletRequest的實(shí)現(xiàn)

Tomcat使用了外觀模式(Facade),這個(gè)實(shí)現(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 實(shí)現(xiàn),它有一個(gè)org.apache.catalina.connector.Request 的對(duì)象。這個(gè)對(duì)象又有一個(gè)org.apache.coyote.Request的對(duì)象,這個(gè)對(duì)象又有一個(gè)org.apache.tomcat.util.http.MimeHeaders 字段,它就是存儲(chǔ)了客戶端請(qǐng)求頭的容器,只要通過(guò)反射獲取到這個(gè)MimeHeaders,對(duì)它進(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中通過(guò)反射對(duì)請(qǐng)求Header進(jìn)行增刪

假設(shè)的場(chǎng)景是,需要對(duì)請(qǐng)求Header統(tǒng)一添加一個(gè)x-request-id,通過(guò)這個(gè)ID來(lái)從日志中定位每一個(gè)請(qǐng)求。

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) {
		// 添加一個(gè)Header,隨機(jī)生成請(qǐng)求ID
		mimeHeaders.addValue("x-request-id").setString(UUID.randomUUID().toString());;
		// 移除一個(gè)header
		mimeHeaders.removeHeader("User-Agent");
	}
}

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

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

SpringBoot默認(rèn)的Servlet容器就是Tomcat

使用Undertow作為容器

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

SpringBoot替換Tomcat為Undertow

只需要把spring-boot-starter-web中的spring-boot-starter-tomcat排除,然后手動(dòng)添加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實(shí)現(xiàn)

它的實(shí)現(xiàn)就比較簡(jiǎn)單

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

io.undertow.servlet.spec.HttpServletRequestImpl實(shí)現(xiàn)類(lèi)中有一個(gè)屬性對(duì)象io.undertow.server.HttpServerExchange,這個(gè)屬性對(duì)象又包含了一個(gè)io.undertow.util.HeaderMap,HeaderMap就是請(qǐng)求Header的存儲(chǔ)容器,反射獲取它就行。

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中通過(guò)反射對(duì)請(qǐng)求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");
	}
}

請(qǐng)求Controller獲取結(jié)果

如何對(duì)HttpServletRequest中的Header進(jìn)行增刪

感謝各位的閱讀,以上就是“如何對(duì)HttpServletRequest中的Header進(jìn)行增刪”的內(nèi)容了,經(jīng)過(guò)本文的學(xué)習(xí)后,相信大家對(duì)如何對(duì)HttpServletRequest中的Header進(jìn)行增刪這一問(wèn)題有了更深刻的體會(huì),具體使用情況還需要大家實(shí)踐驗(yàn)證。這里是億速云,小編將為大家推送更多相關(guān)知識(shí)點(diǎn)的文章,歡迎關(guān)注!

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI