使用Java RestTemplate调用FlightRadar24 API遭Cloudflare 403拦截求助
问题
我尝试用Java + Spring RestTemplate调用FlightRadar24 API获取航班数据,却收到Cloudflare返回的403 Forbidden错误。
需求说明
根据FlightRadar24 API文档,请求需满足:
- 基础URL:
https://fr24api.flightradar24.com/api - Authorization头部携带Bearer格式的API令牌
- Accept-Version头部设置为v1
- 发送GET请求到对应端点
我的代码
package ch.ais.www.services; import java.util.Collections; import org.springframework.http.*; import org.springframework.web.client.RestTemplate; public class Fr24Service { private final RestTemplate restTemplate = new RestTemplate(); private final String apiToken = "your_api_token_here"; private final String baseUrl = "https://fr24api.flightradar24.com/api"; public String getFlightData(String flightId) { String url = String.format("%s/flights/%s", baseUrl, flightId); // Set headers HttpHeaders headers = new HttpHeaders(); headers.setBearerAuth(apiToken); // Set Authorization header headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON)); headers.add("Accept-Version", "v1"); headers.add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64)"); // Create request entity HttpEntity<String> entity = new HttpEntity<>(headers); // Send GET request ResponseEntity<String> response; try { response = restTemplate.exchange( url, HttpMethod.GET, entity, String.class); } catch (HttpClientErrorException e) { // Handle HTTP errors System.err.println("HTTP Status Code: " + e.getStatusCode()); System.err.println("Response Body: " + e.getResponseBodyAsString()); throw e; } if (response.getStatusCode() == HttpStatus.OK) { return response.getBody(); } else { // Error handling throw new RuntimeException("Error fetching flight data: " + response.getStatusCode()); } } }
遇到的错误
运行时抛出异常:
Exception in thread "main" org.springframework.web.client.HttpClientErrorException$Forbidden: 403 Forbidden: "<!DOCTYPE html> <!--[if lt IE 7]> <html class="no-js ie6 oldie" lang="en-US"> <![endif]--> <!--[if IE 7]> <html class="no-js ie7 oldie" lang="en-US"> <![endif]--> <!--[if IE 8]> <html class="no-js ie8 oldie" lang="en-US"> <![endif]--> <!--[if gt IE 8]><!--> <html class="no-js" lang="en-US"> <!--<![endif]--> <head> <title>Attention Required! | Cloudflare</title> ...
Cloudflare拦截了请求,返回HTML验证页面而非预期的JSON响应。
补充信息
使用Java 21 + Spring RestTemplate,Cloudflare将请求识别为自动化流量拦截。API凭证合法,已按文档要求设置必要头部。
已尝试方案
- 验证apiToken正确有效
- 确认Authorization头部为Bearer格式
- 设置Accept-Version为v1
- 添加模拟浏览器的User-Agent头部
- Postman和curl测试请求可正常返回数据
- 确认端点URL无误
- 尝试Spring WebFlux WebClient,仍出现相同403错误
- 启用日志检查请求和响应细节
核心问题
在拥有合法API凭证的情况下,如何配置RestTemplate或其他HTTP客户端,绕过Cloudflare拦截成功请求FlightRadar24 API?
解决方案
1. 完全复刻Postman/curl的请求头
Cloudflare会通过请求头完整性判断是否为自动化流量,Postman能成功则说明它的请求头被认可。打开Postman的「请求详情」,复制所有请求头(包括Accept-Language、Referer、Accept-Encoding等),全部添加到RestTemplate的请求中:
headers.add("Accept-Language", "en-US,en;q=0.9"); headers.add("Referer", "https://www.flightradar24.com/"); headers.add("Accept-Encoding", "gzip, deflate, br"); headers.add("Connection", "keep-alive");
不要遗漏任何Postman发送的头部,尤其是看似无关的字段。
2. 配置RestTemplate支持Cookie管理
Cloudflare可能通过Cookie验证会话,默认RestTemplate的HttpClient未启用Cookie持久化。自定义RestTemplate配置,启用CookieStore:
@Bean public RestTemplate fr24RestTemplate() { CloseableHttpClient httpClient = HttpClientBuilder.create() .setDefaultCookieStore(new BasicCookieStore()) .build(); HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(httpClient); return new RestTemplate(factory); }
使用这个自定义的RestTemplate,确保会话Cookie能被保存和复用。
3. 预请求获取Cloudflare验证Cookie
如果直接请求被拦截,可以先发送不带Authorization的请求到API端点,获取Cloudflare返回的验证Cookie,再携带Cookie和API凭证发送实际请求:
// 第一步:获取Cloudflare会话Cookie HttpHeaders preHeaders = new HttpHeaders(); preHeaders.set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64)"); HttpEntity<String> preEntity = new HttpEntity<>(preHeaders); ResponseEntity<String> preResponse = restTemplate.exchange("https://fr24api.flightradar24.com/api", HttpMethod.GET, preEntity, String.class); // 提取Cookie Set<String> cookies = preResponse.getHeaders().get(HttpHeaders.SET_COOKIE); // 第二步:携带Cookie和API凭证发送请求 HttpHeaders flightHeaders = new HttpHeaders(); flightHeaders.setBearerAuth(apiToken); flightHeaders.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON)); flightHeaders.add("Accept-Version", "v1"); flightHeaders.add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64)"); if (cookies != null) { flightHeaders.put(HttpHeaders.COOKIE, cookies); } // 添加其他复刻的请求头... HttpEntity<String> flightEntity = new HttpEntity<>(flightHeaders); ResponseEntity<String> flightResponse = restTemplate.exchange(url, HttpMethod.GET, flightEntity, String.class);
4. 使用更贴近浏览器的HTTP客户端(如OkHttp)
RestTemplate默认的HttpClient配置不够贴近浏览器行为,换成OkHttp客户端:
先添加OkHttp依赖:
<dependency> <groupId>com.squareup.okhttp3</groupId> <artifactId>okhttp</artifactId> <version>4.12.0</version> </dependency>
再配置RestTemplate使用OkHttp:
@Bean public RestTemplate okHttpRestTemplate() { OkHttpClient okHttpClient = new OkHttpClient.Builder() .cookieJar(new CookieJar() { private final HashMap<String, List<Cookie>> cookieStore = new HashMap<>(); @Override public void saveFromResponse(HttpUrl url, List<Cookie> cookies) { cookieStore.put(url.host(), cookies); } @Override public List<Cookie> loadForRequest(HttpUrl url) { List<Cookie> cookies = cookieStore.get(url.host()); return cookies != null ? cookies : Collections.emptyList(); } }) .build(); OkHttp3ClientHttpRequestFactory factory = new OkHttp3ClientHttpRequestFactory(okHttpClient); return new RestTemplate(factory); }
配合完整的请求头,更容易通过Cloudflare检测。
5. 控制请求频率
Cloudflare会拦截短时间内的高频请求,确保请求频率符合FlightRadar24 API的限制,批量请求时添加适当延迟。
内容的提问来源于stack exchange,提问作者Ivan Leo Otero Mora

