核心概念
在 HTTP 请求中,参数通常存在于以下几个地方:

- 请求体: 主要用于
POST,PUT,PATCH等请求,格式通常是application/x-www-form-urlencoded或application/json。 - 查询字符串: 出现在 URL 的 之后,主要用于
GET请求,但也可用于其他方法,格式是key1=value1&key2=value2。 - 请求头: 包含元数据,如
Content-Type,Authorization等,虽然不是传统意义上的“参数”,但有时也需要修改。
修改参数的核心思路是:获取到请求对象 -> 修改其属性 -> 将修改后的请求继续传递下去。
Servlet 原生 API
在传统的 Servlet 环境中,修改参数比较麻烦,因为 HttpServletRequest 对象是只读的(immutable),你不能直接修改它,常见的解决方案是创建一个请求包装类。
修改查询字符串参数
查询字符串参数是通过 request.getParameter() 获取的,但这个方法底层依赖于解析后的 getParameterMap(),而这个 Map 通常是不可变的,我们只能包装 HttpServletRequest 并重写其方法。
步骤:

- 创建一个
HttpServletRequest的包装类。 - 重写
getParameter(),getParameterMap(),getParameterNames()等方法。 - 在过滤器 中使用这个包装类。
示例代码:
请求包装类 (ModifiableRequestWrapper.java)
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.util.*;
public class ModifiableRequestWrapper extends HttpServletRequestWrapper {
private final Map<String, String[]> modifiableParameters;
public ModifiableRequestWrapper(HttpServletRequest request) {
super(request);
// 将原始参数深拷贝到一个新的可修改的Map中
this.modifiableParameters = new HashMap<>(request.getParameterMap());
}
/**
* 添加或修改一个参数
* @param name 参数名
* @param value 参数值
*/
public void addParameter(String name, String value) {
modifiableParameters.put(name, new String[]{value});
}
/**
* 移除一个参数
* @param name 参数名
*/
public void removeParameter(String name) {
modifiableParameters.remove(name);
}
@Override
public String getParameter(String name) {
String[] values = modifiableParameters.get(name);
return values != null ? values[0] : null;
}
@Override
public Map<String, String[]> getParameterMap() {
// 返回一个不可修改的视图,以防止外部代码修改内部的Map
return Collections.unmodifiableMap(modifiableParameters);
}
@Override
public Enumeration<String> getParameterNames() {
return Collections.enumeration(modifiableParameters.keySet());
}
@Override
public String[] getParameterValues(String name) {
return modifiableParameters.get(name);
}
}
过滤器 (ParameterModifyFilter.java)
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
@WebFilter("/*") // 过滤所有请求
public class ParameterModifyFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
// 将原始请求转换为我们的包装类
ModifiableRequestWrapper wrappedRequest = new ModifiableRequestWrapper((HttpServletRequest) request);
// --- 在这里修改参数 ---
// 示例:将所有名为 "oldName" 的参数修改为 "newName"
String[] oldValues = wrappedRequest.getParameterValues("oldName");
if (oldValues != null) {
wrappedRequest.removeParameter("oldName");
for (String value : oldValues) {
wrappedRequest.addParameter("newName", value);
}
}
// 示例:添加一个固定参数
wrappedRequest.addParameter("source", "web-filter");
// 将包装后的请求传递给下一个过滤器或目标资源
chain.doFilter(wrappedRequest, response);
}
// ... init, destroy 方法 ...
}
修改请求体
修改请求体比修改查询字符串更复杂,因为请求体只能被读取一次,你需要同样使用包装类,并重写 getInputStream() 和 getReader() 方法,使其返回一个包含修改后内容的流。

步骤:
- 创建
HttpServletRequestWrapper。 - 在构造函数中读取并缓存原始请求体。
- 根据你的需求(修改 JSON)解析缓存的内容。
- 重写
getInputStream()或getReader(),返回一个包含修改后内容的新输入流。
示例(修改 JSON 请求体):
import com.fasterxml.jackson.databind.ObjectMapper;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.*;
public class JsonBodyModifyWrapper extends HttpServletRequestWrapper {
private final String modifiedBody;
public JsonBodyModifyWrapper(HttpServletRequest request) throws IOException {
super(request);
// 1. 读取原始请求体
String originalBody = getBodyAsString(request);
// 2. 修改 JSON 内容 (这里使用 Jackson)
ObjectMapper mapper = new ObjectMapper();
Map<String, Object> payload = mapper.readValue(originalBody, Map.class);
// 示例:给 JSON 添加一个新字段
payload.put("processedBy", "java-wrapper");
// 示例:修改一个现有字段
if (payload.containsKey("username")) {
payload.put("username", "modified_" + payload.get("username"));
}
// 3. 将修改后的内容写回
this.modifiedBody = mapper.writeValueAsString(payload);
}
@Override
public ServletInputStream getInputStream() throws IOException {
final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(modifiedBody.getBytes("UTF-8"));
return new ServletInputStream() {
@Override
public boolean isFinished() { return byteArrayInputStream.available() == 0; }
@Override
public boolean isReady() { return true; }
@Override
public void setReadListener(ReadListener readListener) { throw new UnsupportedOperationException(); }
@Override
public int read() throws IOException { return byteArrayInputStream.read(); }
};
}
@Override
public BufferedReader getReader() throws IOException {
return new BufferedReader(new InputStreamReader(this.getInputStream(), "UTF-8"));
}
// 辅助方法:从请求中读取字符串
private String getBodyAsString(HttpServletRequest request) throws IOException {
StringBuilder stringBuilder = new StringBuilder();
BufferedReader bufferedReader = null;
try (InputStream inputStream = request.getInputStream()) {
if (inputStream != null) {
bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
char[] charBuffer = new char[128];
int bytesRead = -1;
while ((bytesRead = bufferedReader.read(charBuffer)) > 0) {
stringBuilder.append(charBuffer, 0, bytesRead);
}
}
} finally {
if (bufferedReader != null) {
try {
bufferedReader.close();
} catch (IOException ex) {
// 忽略
}
}
}
return stringBuilder.toString();
}
}
Spring Boot / Spring MVC
Spring Boot 框架提供了更简洁、更强大的方式来处理请求,特别是使用 HandlerInterceptor(拦截器)。
使用 HandlerInterceptor 修改请求参数
拦截器是处理请求和响应的理想选择,它比 Servlet 过滤器更贴近业务逻辑。
步骤:
- 创建一个
HandlerInterceptor实现类。 - 实现
preHandle方法,这个方法在控制器方法执行之前被调用,是修改请求参数的最佳位置。 - 将拦截器注册到 Spring MVC 中。
示例代码:
拦截器 (ParameterModifyInterceptor.java)
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Map;
@Component // 标记为Spring组件
public class ParameterModifyInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// 获取所有参数的Map
Map<String, String[]> parameterMap = request.getParameterMap();
// 示例:如果请求中有 "token" 参数,则添加一个新的 "auth" 参数
if (parameterMap.containsKey("token")) {
String token = request.getParameter("token");
// 注意:直接修改 request.getParameterMap() 可能无效,因为Map可能是不可变的
// 更好的方式是使用 HttpServletRequestWrapper (见下方完整示例)
// 这里仅作概念演示
System.out.println("Found token: " + token + ". Will add auth header.");
// 实际修改参数需要包装 request,下面会给出完整例子
}
// 返回 true 表示继续流程,false 表示中断流程
return true;
}
}
注册拦截器
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Autowired
private ParameterModifyInterceptor parameterModifyInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(parameterModifyInterceptor)
.addPathPatterns("/**"); // 拦截所有路径
}
}
结合 HttpServletRequestWrapper 的完整 Spring 示例
这是在 Spring 中最健壮的实现方式,结合了拦截器和请求包装。
// 1. 拦截器
@Component
public class AdvancedParameterInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// 使用包装类来处理
if (request instanceof ContentCachingRequestWrapper) {
// 如果已经有包装,直接使用
return true;
}
return true;
}
@Override
public void afterConcurrentHandlingStarted(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// 确保流被关闭,以便后续读取
if (request instanceof ContentCachingRequestWrapper) {
((ContentCachingRequestWrapper) request).getContentAsByteArray();
}
}
}
// 2. 在配置类中应用包装器和拦截器
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new AdvancedParameterInterceptor())
.addPathPatterns("/**");
}
@Bean
public FilterRegistrationBean<OncePerRequestFilter> contentCachingFilter() {
FilterRegistrationBean<OncePerRequestFilter> registrationBean = new FilterRegistrationBean<>();
registrationBean.setFilter(new OncePerRequestFilter() {
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
// 使用Spring提供的ContentCachingRequestWrapper来缓存请求体
ContentCachingRequestWrapper cachingRequest = new ContentCachingRequestWrapper(request);
filterChain.doFilter(cachingRequest, response);
}
});
registrationBean.addUrlPatterns("/*");
registrationBean.setOrder(Ordered.HIGHEST_PRECEDENCE);
return registrationBean;
}
}
// 3. Controller
@RestController
@RequestMapping("/api")
public class MyController {
@GetMapping("/data")
public String getData(@RequestParam String id, @RequestParam(required = false) String newName) {
System.out.println("Controller received - id: " + id + ", newName: " + newName);
return "Processed id: " + id;
}
}
注意:Spring 提供了
ContentCachingRequestWrapper,它是一个非常有用的 Servlet 请求包装器,可以缓存请求体,让你多次读取它,上面的例子展示了如何结合使用它。
使用 HTTP 客户端发送请求
如果你不是在服务端修改收到的请求,而是在客户端(如调用其他微服务)时修改要发送的请求,那就简单多了。
使用 RestTemplate (旧版)
import org.springframework.http.*;
import org.springframework.web.client.RestTemplate;
import java.util.Collections;
public class RestTemplateExample {
public static void main(String[] args) {
RestTemplate restTemplate = new RestTemplate();
// 1. 准备URL和参数
String url = "http://example.com/api/data";
// 修改查询参数
UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(url)
.queryParam("id", "123") // 设置或覆盖 id 参数
.queryParam("from", "my-client"); // 添加新参数
// 2. 准备请求体 (如果是 POST/PUT)
MultiValueMap<String, String> body = new LinkedMultiValueMap<>();
body.add("original_key", "original_value");
body.add("modified_key", "new_value"); // 修改或添加请求体参数
// 3. 设置请求头
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
headers.set("Authorization", "Bearer token123");
HttpEntity<MultiValueMap<String, String>> entity = new HttpEntity<>(body, headers);
// 4. 发送请求
ResponseEntity<String> response = restTemplate.exchange(
builder.build().toUri(),
HttpMethod.POST,
entity,
String.class);
System.out.println(response.getBody());
}
}
使用 WebClient (新版,推荐)
WebClient 是 Spring 5 引入的响应式 HTTP 客户端,更加灵活。
import org.springframework.http.MediaType;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Mono;
public class WebClientExample {
public static void main(String[] args) {
WebClient webClient = WebClient.create("http://example.com");
// 修改查询参数和请求体
Mono<String> response = webClient.post()
.uri(uriBuilder -> uriBuilder
.path("/api/data")
.queryParam("id", "456") // 修改查询参数
.queryParam("source", "web-client") // 添加查询参数
.build())
.contentType(MediaType.APPLICATION_JSON)
.bodyValue("{\"original_field\": \"value\", \"updated_field\": \"new_value\"}") // 直接修改JSON请求体
.retrieve()
.bodyToMono(String.class);
// 订阅并打印结果
response.subscribe(System.out::println);
}
}
| 场景 | 核心工具/方法 | 关键点 |
|---|---|---|
| 服务端修改请求 | ||
| Servlet 环境 | HttpServletRequestWrapper + Filter |
必须包装请求对象,因为原生 request 是只读的。 |
| Spring Boot | HandlerInterceptor + HttpServletRequestWrapper (如 ContentCachingRequestWrapper) |
拦截器是切入点,包装是实现修改的手段。 |
| 客户端发送请求 | ||
RestTemplate |
UriComponentsBuilder (查询参数), HttpEntity (请求体/头) |
直接构建 UriComponents 和 HttpEntity 来设置你想要的任何参数。 |
WebClient |
uri() (查询参数), bodyValue() (请求体) |
在链式调用中,通过 uri() builder 和 bodyValue() 方法轻松修改。 |
希望这个详细的解释能帮助你解决在 Java 中修改请求参数的问题!
