You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Boot接收MultipartFile时自定义请求头丢失问题求助

问题:Multipart请求中自定义请求头无法被Spring Boot后端获取

项目基于Spring Boot(后端)和React(前端),需通过自定义请求头实现服务端请求追踪。当前遇到异常:使用@RequestPart接收MultipartFile时,后端无法获取前端已发送的自定义请求头(浏览器开发者工具已确认前端请求头正常发出);但移除MultipartFile参数及对应consumes配置后,请求头可正常读取。


后端Spring Boot代码

@PostMapping(value = "/url", consumes = {MediaType.APPLICATION_JSON_VALUE, MediaType.MULTIPART_FORM_DATA_VALUE})
public CommandResponse registerCommand(@RequestPart("command") RegisterCommand command, @RequestPart(value="files", required = false)  List<MultipartFile> files) {
        command.validate();
        String responseId = logicFlow.registerComand(command.getId(), command.getMessage(), files);
        command.setResponse(responseId);
        return command.getResponse();
    }

前端React代码

const registerCommand = (variables: { id: string, message: Message, files?: File[] }) => {
  const form = new FormData();
  const command = <RegisterCommand>{ ...variables };

  const blob = new Blob([JSON.stringify(command)], {
    type: 'application/json',
  });

  if (variables.files) {
    for (const file of variables.files) {
      form.append('files', file);
    }
  }

 form.set('command', blob);

  return axios.post<CommandResponse>(
    url(`/url`),
    form);
};

Axios请求拦截器代码

axios.interceptors.request.use(
    config => {
      const key = 'dock.context';
      const value = window ? window.sessionStorage.getItem(key) ?? window.localStorage.getItem(key) : '';
      if (!value) {
        return config;
      }

      const context = JSON.parse(value);
      config.headers['X-Trail-Scene-url'] = window.location.href;
      config.headers['X-Trail-Endpoint'] = config.url;
      config.headers['X-Trail-Actor-Id'] = context?.actor?.id || '0@0:0:0:0-0';
      config.headers['X-Trail-Cs-Time'] = Date.now();
      config.headers['X-Trail-Location'] = geoLocation;

      return config
    },
    error => {
      Promise.reject(error)
    }
  )

解决方案

1. 调整Spring Boot Multipart解析器配置

Spring Boot默认的Multipart解析器可能提前消耗请求体,导致请求头读取异常。显式配置解析器并禁用延迟解析:

@Configuration
public class MultipartConfig {
    @Bean
    public MultipartResolver multipartResolver() {
        StandardServletMultipartResolver resolver = new StandardServletMultipartResolver();
        resolver.setResolveLazily(false); // 确保请求头优先被处理
        return resolver;
    }
}

2. 前端避免手动设置Content-Type

发送FormData时,不要手动指定Content-Type,让浏览器自动生成带boundary的multipart/form-data头。Axios默认会处理此逻辑,若有全局配置覆盖需修正:

return axios.post<CommandResponse>(
    url(`/url`),
    form,
    {
        headers: {
            'Content-Type': undefined // 让浏览器自动生成正确的multipart请求头
        }
    }
);

3. 后端直接用@RequestHeader绑定自定义头

在接口方法中显式通过@RequestHeader获取自定义头,确保Multipart场景下能正常读取:

public CommandResponse registerCommand(
    @RequestPart("command") RegisterCommand command, 
    @RequestPart(value="files", required = false) List<MultipartFile> files,
    @RequestHeader("X-Trail-Scene-url") String sceneUrl,
    @RequestHeader("X-Trail-Endpoint") String endpoint,
    @RequestHeader("X-Trail-Actor-Id") String actorId
) {
    // 使用获取到的请求头做追踪处理
    command.validate();
    String responseId = logicFlow.registerComand(command.getId(), command.getMessage(), files);
    command.setResponse(responseId);
    return command.getResponse();
}

4. 排查跨域配置(若前后端跨域部署)

确保后端CORS配置允许自定义请求头通过:

@Configuration
public class CorsConfig {
    @Bean
    public CorsFilter corsFilter() {
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        CorsConfiguration config = new CorsConfiguration();
        config.setAllowCredentials(true);
        config.addAllowedOriginPattern("*"); // 根据实际部署域名调整
        config.addAllowedHeader("*"); // 或明确列出所有自定义请求头
        config.addAllowedMethod("*");
        source.registerCorsConfiguration("/**", config);
        return new CorsFilter(source);
    }
}

内容的提问来源于stack exchange,提问作者Mamurbek

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.01 22:17:39