AWS CloudFront接口Postman调用正常,Spring WebClient返回400错误
问题描述
我有一个部署在AWS CloudFront上的API,使用Postman测试时调用正常,但通过Spring WebClient调用该API时,返回400 Bad Request错误。
Postman请求情况
Postman请求正常,请求截图如下:
WebClient调用返回的错误响应
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <HTML><HEAD><META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> <TITLE>ERROR: The request could not be satisfied</TITLE> </HEAD><BODY> <H1>400 ERROR</H1> <H2>The request could not be satisfied.</H2> <HR noshade size="1px"> Bad request. We can't connect to the server for this app or website at this time. There might be too much traffic or a configuration error. Try again later, or contact the app or website owner. <BR clear="all"> If you provide content to customers through CloudFront, you can find steps to troubleshoot and help prevent this error by reviewing the CloudFront documentation. <BR clear="all"> <HR noshade size="1px"> <PRE> Generated by cloudfront (CloudFront) Request ID: pGx0NHPSaU3H2EHJwtQrYEdLDjL_UPxO90esPoH3d9efZX_bvzjFQw== </PRE> <ADDRESS> </ADDRESS> </BODY></HTML>
我的WebClient代码
@Component public class SyncTranscriberClient { private final WebClient webClient; @Value("${transcriber.sync.username}") private String username; @Value("${transcriber.sync.password}") private String password; public SyncTranscriberClient(@Value("${transcriber.sync.base-url}") String baseUrl) throws SSLException { var sslContext = SslContextBuilder .forClient() .trustManager(InsecureTrustManagerFactory.INSTANCE) .build(); var client = HttpClient.create().secure(t -> t.sslContext(sslContext)); webClient = WebClient.builder() .clientConnector(new ReactorClientHttpConnector(client)) .baseUrl(baseUrl) .filter(logRequest()) .build(); } private static ExchangeFilterFunction logRequest() { return ExchangeFilterFunction.ofRequestProcessor(clientRequest -> { log.info("Request: {} {}", clientRequest.method(), clientRequest.url()); clientRequest.headers().forEach((name, values) -> values.forEach(value -> log.info("{}={}", name, value))); return Mono.just(clientRequest); }); } public Map<String, String> getCredentials() { return webClient.post() .uri("my-url-hidden-for-security-reasons") .headers(headers -> headers.setBasicAuth(username, password)) .headers(headers -> headers.set("Accept", "*/*")) .headers(headers -> headers.set("Host", "hidden-for-security-reasons")) .retrieve() .onStatus(HttpStatus::isError, response -> response.bodyToMono(String.class) // error body as String or other class .flatMap(error -> Mono.error(new RuntimeException(error))) ) .toBodilessEntity() .map(HttpEntity::getHeaders) .map(headers -> Map.of( "Authorization", Objects.requireNonNull(headers.getFirst("Authorization")), "JSESSIONID", Objects.requireNonNull(headers.getFirst("JSESSIONID")) )) .block(); } }
请问我哪里操作出错了?
可能的问题及解决方法
1. 请求Body缺失或格式不匹配
Postman调用时可能自动添加了默认Body(比如空Body),但你的WebClient调用使用.toBodilessEntity(),未发送任何请求Body。如果后端API要求POST请求必须包含Body(哪怕是空的),CloudFront或源服务器会返回400。
解决方法:
添加空Body或匹配Postman的Body内容,示例:
.webClient.post() .uri("your-uri") // ...其他配置 .bodyValue("") // 或根据实际需求传对应格式的Body .retrieve() // ...后续逻辑
2. Host头设置问题
手动设置的Host头可能与CloudFront分发的域名不匹配,或者和Postman实际发送的Host头不一致,导致CloudFront校验失败。
解决方法:
- 对比Postman中的Host头值,确保代码里的
Host头完全一致; - 尝试移除手动设置的Host头,让WebClient根据请求URL自动生成:
// 删除这一行手动设置Host的代码 // .headers(headers -> headers.set("Host", "hidden-for-security-reasons"))
3. Basic Auth编码不一致
WebClient的setBasicAuth会自动对用户名密码做Base64编码,但如果Postman中你是手动输入编码后的Authorization值(而非用Postman自动生成),可能存在字符集或编码逻辑差异。
解决方法:
- 对比WebClient日志输出的
Authorization头和Postman中的对应值是否完全一致; - 若不一致,手动构造Basic Auth头:
import java.util.Base64; import java.nio.charset.StandardCharsets; // ... String auth = Base64.getEncoder().encodeToString((username + ":" + password).getBytes(StandardCharsets.UTF_8)); .headers(headers -> headers.set("Authorization", "Basic " + auth))
4. 请求头遗漏或重复设置
对照Postman的请求头和WebClient日志输出的头,检查是否有遗漏(比如Content-Type)或重复设置的头导致冲突。
解决方法:
- 补充缺失的请求头;
- 将所有头设置合并到一个
.headers()调用中,避免重复覆盖:
.headers(headers -> { headers.setBasicAuth(username, password); headers.set("Accept", "*/*"); // 其他需要的头统一在这里添加 })
5. CloudFront WAF或缓存拦截
CloudFront关联的WAF规则可能将WebClient请求识别为异常流量拦截,或者旧缓存配置导致错误。
解决方法:
- 检查CloudFront的WAF规则,确认是否有拦截该请求的规则;
- 尝试Invalidate CloudFront缓存,或临时关闭WAF测试是否能正常调用。
内容的提问来源于stack exchange,提问作者Drunken Daddy
相关产品推荐
相关产品推荐

