Understanding Cross-Origin Issues and Solutions with Spring Cloud Gateway and HttpClient
This article explains why browsers enforce same‑origin policies causing CORS problems, outlines common remedies such as the @CrossOrigin annotation, HttpClient usage, and Spring Cloud Gateway integration, and provides detailed configuration and code examples for implementing these solutions in a Java backend.
Because browsers enforce the same‑origin policy, requests from different ports, protocols, or domains trigger cross‑origin (CORS) restrictions, preventing interaction for security reasons.
Common ways to resolve CORS include adding the @CrossOrigin annotation in controller layers, using HttpClient (which does not rely on a browser), or routing requests through an API gateway.
Spring Cloud Gateway Integration
Spring Cloud Gateway replaces Netflix Zuul, offering unified routing and filter capabilities such as security, monitoring, and rate limiting. Its core concepts are:
Routing : defines an ID, target URL, predicates, and filters; a request matches a route when its predicates evaluate to true.
Predicates : functions (e.g., ServerWebExchange) that inspect request attributes like headers or parameters.
Filters : either GatewayFilter or GlobalFilter, which can modify requests and responses.
The gateway receives a request, matches it via GatewayHandlerMapping, forwards it to the appropriate service through the filter chain, and returns the response.
Project Setup
Create a new module service_gateway and add the following Maven dependencies:
<dependencies>
<!-- Common utilities -->
<dependency>
<groupId>com.lzq</groupId>
<artifactId>service_utils</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
</dependencies>Configuration (application.yml or properties):
# Service port
server.port=9090
# Service name
spring.application.name=service-gateway
# Nacos address
spring.cloud.nacos.discovery.server-addr=127.0.0.1:8888
# Enable discovery‑based routing
spring.cloud.gateway.discovery.locator.enabled=true
# Route definitions
spring.cloud.gateway.routes[0].id=service-hosp
spring.cloud.gateway.routes[0].uri=lb://service-hosp
spring.cloud.gateway.routes[0].predicates=Path=/*/hosp/**
spring.cloud.gateway.routes[1].id=service-cmn
spring.cloud.gateway.routes[1].uri=lb://service-cmn
spring.cloud.gateway.routes[1].predicates=Path=/*/cmn/**
spring.cloud.gateway.routes[2].id=service-user
spring.cloud.gateway.routes[2].uri=lb://service-user
spring.cloud.gateway.routes[2].predicates=Path=/*/userlogin/**Startup class:
@SpringBootApplication
public class ApiGatewayApplication {
public static void main(String[] args) {
SpringApplication.run(ApiGatewayApplication.class, args);
}
}Adjust the front‑end .env file to point to the gateway port, and the gateway will handle CORS by allowing the request to pass through to downstream services.
HttpClient Usage
Typical scenarios for HttpClient include inter‑system API calls and web crawling. A simple example of fetching a page with Java's native HttpURLConnection:
public class HttpTest {
@Test
public void test1() throws Exception {
String url = "https://www.baidu.com";
URL url1 = new URL(url);
URLConnection urlConnection = url1.openConnection();
HttpURLConnection httpURLConnection = (HttpURLConnection) urlConnection;
httpURLConnection.setRequestMethod("GET");
httpURLConnection.setRequestProperty("Accept-Charset", "utf-8");
InputStream is = httpURLConnection.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8));
String line;
while ((line = br.readLine()) != null) {
System.out.println(line);
}
}
}Using Apache HttpClient:
Create an HttpClient instance.
Instantiate HttpGet or HttpPost with the target URL.
Set parameters via setParams (for both GET and POST) or setEntity (for POST).
Execute the request with client.execute(request) to obtain an HttpResponse.
Extract headers with getAllHeaders() or getHeaders(String name), and retrieve the response body via getEntity().
Always release the connection after use.
Dependency for Maven:
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.13</version>
</dependency>Example test method:
@Test
public void test2() {
CloseableHttpClient client = HttpClients.createDefault();
String url = "https://www.baidu.com";
HttpGet httpGet = new HttpGet(url);
CloseableHttpResponse response = null;
try {
response = client.execute(httpGet);
String result = EntityUtils.toString(response.getEntity(), "utf-8");
System.out.println(result);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (client != null) {
try { client.close(); } catch (IOException e) { e.printStackTrace(); }
}
}
}Helper Utilities
HttpRequestHelperencapsulates synchronous POST requests:
public static JSONObject sendRequest(Map<String, Object> paramMap, String url) {
String result = "";
try {
StringBuilder postdata = new StringBuilder();
for (Map.Entry<String, Object> param : paramMap.entrySet()) {
postdata.append(param.getKey()).append("=").append(param.getValue()).append("&");
}
byte[] reqData = postdata.toString().getBytes("utf-8");
byte[] respdata = HttpUtil.doPost(url, reqData);
result = new String(respdata);
} catch (Exception ex) {
ex.printStackTrace();
}
return JSONObject.parseObject(result);
} HttpUtilperforms low‑level HTTP operations:
public static byte[] send(String strUrl, String reqmethod, byte[] reqData) {
try {
URL url = new URL(strUrl);
HttpURLConnection httpcon = (HttpURLConnection) url.openConnection();
httpcon.setDoOutput(true);
httpcon.setDoInput(true);
httpcon.setConnectTimeout(CONN_TIMEOUT);
httpcon.setReadTimeout(READ_TIMEOUT);
httpcon.setRequestMethod(reqmethod);
if (reqmethod.equalsIgnoreCase("POST")) {
OutputStream os = httpcon.getOutputStream();
os.write(reqData);
os.flush();
os.close();
}
BufferedReader in = new BufferedReader(new InputStreamReader(httpcon.getInputStream(), "utf-8"));
StringBuilder sb = new StringBuilder();
String line;
while ((line = in.readLine()) != null) {
sb.append(line);
}
in.close();
httpcon.disconnect();
return sb.toString().getBytes();
} catch (Exception ex) {
log.error(ex.toString(), ex);
return null;
}
}These utilities enable different systems to call each other’s APIs, such as a hospital service saving data via a POST request to /api/hosp/saveHospital.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Architect's Guide
Dedicated to sharing programmer-architect skills—Java backend, system, microservice, and distributed architectures—to help you become a senior architect.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
