修改request請求的header請求頭實(shí)現(xiàn)方式
問題和場景
默認(rèn)http傳輸不能中途修改http內(nèi)容, 但是有很多時(shí)候都需要去修改請求頭信息來達(dá)到某些目的,比如我這個(gè)情況:
我需要去修改Authorization請求頭來替換token,我在網(wǎng)上看了好多博客都是HttpServletRequest類的或者是想用反射解決,但是我這里(ServerHttpRequest)并不適用,于是我去求助大佬后得出2個(gè)解決方案,并且ServerHttpRequest和HttpServletRequest都適用。

如果直接set值會(huì)有如下問題:
java.lang.UnsupportedOperationException:null;
at org.springframework.http.ReadOnlyHttpHeaders.set:

解決(ServerHttpRequest)
方案一 直接開放權(quán)限
這個(gè)方法主要是為了兼容以前的代碼,因?yàn)檫@個(gè)header到其他方法里面還會(huì)改 所以我改了header對(duì)象
//設(shè)置為可修改的 headers= HttpHeaders.writableHttpHeaders(headers); //設(shè)置請求頭 headers.set(HttpHeaders.AUTHORIZATION,authorization);
方案二 去修改header
這個(gè)是等于重新build對(duì)象 ,貌似更方便
exchange.getRequest().mutate().header(HttpHeaders.AUTHORIZATION,authorization).build();
上面2種方法都可以實(shí)現(xiàn)這個(gè)效果
修改請求前:

修改請求后:

完整代碼如下:
package org.dromara.soul.bootstrap.filter;
import com.alibaba.nacos.client.utils.StringUtils;
import org.dromara.soul.bootstrap.template.RedisStrTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebFilter;
import org.springframework.web.server.WebFilterChain;
import reactor.core.publisher.Mono;
import reactor.util.annotation.Nullable;
import javax.xml.soap.MimeHeaders;
import java.lang.reflect.Field;
import java.util.List;
/**
* @Auther: whhh
* @Date: 2021/4/1 10:46
* @Description: token替換
*/
@Order(-98)
@Component
public class GetTokenFilter implements WebFilter {
@Autowired
private RedisStrTemplate redisStrTemplate;
@Override
public Mono<Void> filter(@Nullable final ServerWebExchange exchange, @Nullable final WebFilterChain chain) {
ServerHttpRequest request = exchange.getRequest();
//判斷是否包含認(rèn)證頭
if (request.getHeaders().containsKey(HttpHeaders.AUTHORIZATION)) {
HttpHeaders headers = request.getHeaders();
//獲取認(rèn)證集合
List<String> keys = headers.get(HttpHeaders.AUTHORIZATION);
if (keys != null) {
//多個(gè)認(rèn)證取第一個(gè)不為空的
for (String token : keys) {
if (token != null && !token.equals("")) {
//從Redis獲取token
String a = (String) redisStrTemplate.get(token);
String authorization = a.substring(1,a.length()-1);//
//方法一 設(shè)置為可修改的
headers= HttpHeaders.writableHttpHeaders(headers);
//設(shè)置請求頭
headers.set(HttpHeaders.AUTHORIZATION,authorization);
//方法二 bulid
// exchange.getRequest().mutate().header(HttpHeaders.AUTHORIZATION,authorization).build();
if (request.getMethod() == HttpMethod.OPTIONS) {
exchange.getResponse().setStatusCode(HttpStatus.OK);
return Mono.empty();
}
}
}
}
}
return chain.filter(exchange);
}
}
PS:我這個(gè)filter是soul網(wǎng)關(guān)(shenyu)的哦,可能chain有區(qū)別,你可以參考直接創(chuàng)建一個(gè)filter
解決(HttpServletRequest)
你可以自定義個(gè)RemoteAddrFilter,然后通過覆蓋HttpServletRequestWrapper去替換原有的方法,基于HttpServletRequest 創(chuàng)建SafeboxRequestWrapper對(duì)象,然后把SafeboxRequestWrapper對(duì)象作為HttpServletRequest傳遞下去
代碼如下:
HeaderMapRequestWrapper類
package org.dromara.soul.bootstrap.filter;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
/**
* @Auther: whhh
* @Date: 2021/4/26 19:00
* @Description:
*/
public class HeaderMapRequestWrapper extends HttpServletRequestWrapper{
public HeaderMapRequestWrapper(HttpServletRequest request) {
super(request);
}
private Map<String, String> headerMap = new HashMap<String, String>();
/**
* add a header with given name and value
*
* @param name
* @param value
*/
public void addHeader(String name, String value) {
headerMap.put(name, value);
}
@Override
public String getHeader(String name) {
String headerValue = super.getHeader(name);
if (headerMap.containsKey(name)) {
headerValue = headerMap.get(name);
}
return headerValue;
}
/**
* get the Header names
*/
@Override
public Enumeration<String> getHeaderNames() {
List<String> names = Collections.list(super.getHeaderNames());
for (String name : headerMap.keySet()) {
names.add(name);
}
return Collections.enumeration(names);
}
@Override
public Enumeration<String> getHeaders(String name) {
List<String> values = Collections.list(super.getHeaders(name));
if (headerMap.containsKey(name)) {
values.add(headerMap.get(name));
}
return Collections.enumeration(values);
}
}
GetTokenFilter類
package org.dromara.soul.bootstrap.filter;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
/**
* @Auther: whhh
* @Date: 2021/4/26 18:58
* @Description:
*/
@Order(-98)
@Component
public class GetTokenFilter implements Filter{
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
HeaderMapRequestWrapper requestWrapper = new HeaderMapRequestWrapper(req);
//校驗(yàn)請求request Header中是否有對(duì)應(yīng)值
String authorization = request.getParameter(HttpHeaders.AUTHORIZATION);
if (language !=null && !"".equals(authorization)) {
//如果get請求url中帶有這個(gè)參數(shù),則request中新增一個(gè)header
requestWrapper.addHeader(HttpHeaders.AUTHORIZATION, authorization);
// Goes to default servlet.
chain.doFilter(requestWrapper, response);
}
// Goes to default servlet.
chain.doFilter(request, response);
}
@Override
public void destroy() {
}
}
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
微信小程序訂閱消息推送實(shí)戰(zhàn)圖文教程(Java?Spring?Boot?+?Redis)
訂閱消息是微信小程序提供的一種消息推送方式,用戶可以訂閱某個(gè)公眾號(hào)或小程序的消息,當(dāng)有新消息時(shí),系統(tǒng)會(huì)自動(dòng)推送通知給用戶,這篇文章主要介紹了微信小程序訂閱消息推送(Java Spring Boot+Redis)的相關(guān)資料,需要的朋友可以參考下2026-04-04
Java全面細(xì)致講解Cookie與Session及kaptcha驗(yàn)證碼的使用
web開發(fā)階段我們主要是瀏覽器和服務(wù)器之間來進(jìn)行交互。瀏覽器和服務(wù)器之間的交互就像人和人之間進(jìn)行交流一樣,但是對(duì)于機(jī)器來說,在一次請求之間只是會(huì)攜帶著本次請求的數(shù)據(jù)的,但是可能多次請求之間是會(huì)有聯(lián)系的,所以提供了會(huì)話機(jī)制2022-06-06
SpringBoot結(jié)果封裝和異常攔截的實(shí)現(xiàn)示例
SpringBoot 項(xiàng)目中,我們通常需要將結(jié)果數(shù)據(jù)封裝成特定的格式,以方便客戶端進(jìn)行處理,本文主要介紹了SpringBoot?優(yōu)雅的結(jié)果封裝和異常攔截,感興趣的可以了解一下2023-08-08
Spring如何按業(yè)務(wù)模塊輸出日志到不同的文件詳解
最近做項(xiàng)目時(shí)有一個(gè)記錄操作日志的需求,比如某個(gè)用戶進(jìn)行了查詢、刪除、修改等操作,下面這篇文章主要給大家介紹了關(guān)于Spring如何按業(yè)務(wù)模塊輸出日志到不同文件的相關(guān)資料,需要的朋友可以參考下2022-05-05
Spring Boot參數(shù)校驗(yàn)及分組校驗(yàn)的使用教程
在日常的開發(fā)中,參數(shù)校驗(yàn)是非常重要的一個(gè)環(huán)節(jié),嚴(yán)格參數(shù)校驗(yàn)會(huì)減少很多出bug的概率,增加接口的安全性,下面這篇文章主要給大家介紹了關(guān)于Spring Boot參數(shù)校驗(yàn)及分組校驗(yàn)使用的相關(guān)資料,需要的朋友可以參考下2021-08-08
基于SpringBoot+WebSocket實(shí)現(xiàn)網(wǎng)頁在線聊天室
文章介紹了從零構(gòu)建一套前后端分離的網(wǎng)頁聊天室系統(tǒng),涵蓋架構(gòu)設(shè)計(jì)、數(shù)據(jù)庫設(shè)計(jì)、登錄認(rèn)證、WebSocket實(shí)時(shí)消息推送及全局異常處理等核心功能,文章詳細(xì)描述了前端頁面與交互、后端技術(shù)棧及核心功能實(shí)現(xiàn)、數(shù)據(jù)庫設(shè)計(jì)等以及項(xiàng)目運(yùn)行等等內(nèi)容,需要的朋友可以參考下2026-05-05
MyBatis-Plus整合金倉數(shù)據(jù)庫KingbaseES的實(shí)戰(zhàn)指南
隨著數(shù)字中國建設(shè)的深入推進(jìn),國產(chǎn)數(shù)據(jù)庫在關(guān)鍵業(yè)務(wù)系統(tǒng)中扮演著越來越重要的角色,本文將通過一個(gè)電商系統(tǒng)的實(shí)戰(zhàn)案例,深入探討MyBatis-Plus整合KingbaseES的詳細(xì)步驟吧2025-10-10

