當前位置: 妍妍網 > 碼農

三種跨域解決方案:HttpClient、註解、閘道器

2024-01-31碼農

點選關註公眾號,Java幹貨 及時送達 👇

為什麽會有跨域問題

因為瀏覽器的同源政策,就會產生跨域。比如說發送的異步請求是不同的兩個源,就比如是不同的的兩個埠或者不同的兩個協定或者不同的網域名稱。由於瀏覽器為了安全考慮,就會產生一個同源政策,不是同一個地方出來的是不允許進行互動的。

常見的跨域解決方式
  1. 在控制層加入允許跨域的註解 @CrossOrigin

  2. 使用 httpclient ,不依賴瀏覽器

  3. 使用閘道器 Gateway

註解:@CrossOrigin

在控制層加入允許跨域的註解,即可完成一個計畫中前後埠跨域的問題

閘道器整合

Spring Cloud Gateway 作為Spring Cloud生態系中的閘道器,目標是替代 Netflix Zuul ,其 不僅提供統一的路由方式,並且還基於Filer鏈的方式提供了閘道器基本的功能,例如:安全、監 控/埋點、限流等。

(1)路由

路由是閘道器最基礎的部份,路由資訊有一個ID、一個目的URL、一組斷言和一組 Filter組成。如果斷言路由為真,則說明請求的URL和配置匹配

(2)斷言

Java8中的斷言函式。 Spring Cloud Gateway 中的斷言函式輸入型別是Spring5.0框 架中的 ServerWebExchange Spring Cloud Gateway 中的斷言函式允許開發者去定義匹配來自 於 http request 中的任何資訊,比如請求頭和參數等。

(3)過濾器

一個標準的 Spring webFilter Spring cloud gateway 中的filter分為兩種型別的 Filter,分別是 Gateway Filter Global Filter 。過濾器Filter將會對請求和響應進行修改處理

Spring cloud Gateway 發出請求。然後再由 Gateway Handler Mapping 中找到與請 求相匹配的路由,將其發送到 Gateway web handler 。Handler再透過指定的過濾器鏈將請求發 送到實際的服務執行業務邏輯,然後返回。

計畫中使用

新建模組 service_gateway

<dependencies>
<!-- 公共模組依賴 -->
<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>

配置檔

#伺服端口
server.port=9090
# 服務名
spring.application.name=service-gateway
# nacos服務地址 預設8848
spring.cloud.nacos.discovery.server-addr=127.0.0.1:8888
#使用服務發現路由
spring.cloud.gateway.discovery.locator.enabled=true
#設定路由id
spring.cloud.gateway.routes[0].id=service-hosp
#設定路由的uri lb負載均衡
spring.cloud.gateway.routes[0].uri=lb://service-hosp
#設定路由斷言,代理servicerId為auth-service的/auth/路徑
spring.cloud.gateway.routes[0].predicates= Path=/*/hosp/**
#設定路由id
spring.cloud.gateway.routes[1].id=service-cmn
#設定路由的uri
spring.cloud.gateway.routes[1].uri=lb://service-cmn
#設定路由斷言,代理servicerId為auth-service的/auth/路徑
spring.cloud.gateway.routes[1].predicates= Path=/*/cmn/**
#設定路由id
spring.cloud.gateway.routes[2].id=service-hosp
#設定路由的uri
spring.cloud.gateway.routes[2].uri=lb://service-hosp
#設定路由斷言,代理servicerId為auth-service的/auth/路徑
spring.cloud.gateway.routes[2].predicates= Path=/*/userlogin/**

建立啟動類

@SpringBootApplication
public class ApiGatewayApplication {
public static void main(String[] args) {
SpringApplication.run(ApiGatewayApplication. class, args);
}
}

修改前端 .evn 檔,改成存取閘道器埠號

做集群部署時,他會根據名稱實作負載均衡

跨域理解:發送請求後,閘道器過濾器會進行請求攔截,將跨域放行,轉發到伺服器中

跨域配置類

@Configuration
public class CorsConfig {
@Bean
public CorsWebFilter corsFilter() {
CorsConfiguration config = new CorsConfiguration();
config.addAllowedMethod("*");
config.addAllowedOrigin("*");
config.addAllowedHeader("*");
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(new PathPatternParser());
source.registerCorsConfiguration("/**", config);
return new CorsWebFilter(source);
}
}

若之前采用註解跨域,需要將 @CrossOrigin 去掉

Httpclient

常見的使用場景:多系統之間介面的互動、爬蟲

http原生請求,獲取百度首頁程式碼

public class HttpTest {
@Test
public void test1() throws Exception {
String url = "https://www.badu.com";
URL url1 = new URL(url);
//url連線
URLConnection urlConnection = url1.openConnection();
HttpURLConnection httpURLConnection = (HttpURLConnection)urlConnection;
//獲取httpURLConnection輸入流
InputStream is = httpURLConnection.getInputStream();
//轉換為字串
InputStreamReader reader = new InputStreamReader(is, StandardCharsets.UTF_8);
BufferedReader br = new BufferedReader(reader);
String line;
//將字串一行一行讀取出來
while ((line = br.readLine())!= null){
System.out.println(line);
}
}
}
//設定請求型別
httpURLConnection.setRequestMethod("GET");
//請求包含 請求行、空格、請求頭、請求體
//設定請求頭編碼
httpURLConnection.setRequestProperty("Accept-Charset","utf-8");

使用 HttpClient 發送請求、接收響應

  1. 建立 HttpClient 物件。

  2. 建立請求方法的例項,並指定請求URL。如果需要發送GET請求,建立 HttpGet 物件;如果需要發送POST請求,建立 HttpPost 物件。

  3. 如果需要發送請求參數,可呼叫 HttpGet HttpPost 共同的 setParams(HetpParams params) 方法來添加請求參數;對於 HttpPost 物件而言,也可呼叫 setEntity(HttpEntity entity) 方法來設定請求參數。

  4. 呼叫 HttpClient 物件的 execute(HttpUriRequest request) 發送請求,該方法返回一個 HttpResponse

  5. 呼叫 HttpResponse getAllHeaders() getHeaders(String name) 等方法可獲取伺服器的響應頭;呼叫 HttpResponse getEntity() 方法可獲取 HttpEntity 物件,該物件包裝了伺服器的響應內容。程式可透過該物件獲取伺服器的響應內容。

  6. 釋放連線。無論執行方法是否成功,都必須釋放連線

整合測試,添加依賴

<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.13</version>
</dependency>
@Test
public void test2(){
//可關閉的httpclient客戶端,相當於開啟一個瀏覽器
CloseableHttpClient client = HttpClients.createDefault();
String url = "https://www.baidu.com";
//構造httpGet請求物件
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();
}
}
}
}

計畫中使用,系統呼叫平台介面保存資訊,根據傳入josn數據保存資訊

系統中

@RequestMapping(value="/hospital/save",method=RequestMethod.POST)
public String saveHospital(String data, HttpServletRequest request) {
 try {
apiService.saveHospital(data);
 } catch (YyghException e) {
return this.failurePage(e.getMessage(),request);
 } catch (Exception e) {
return this.failurePage("數據異常",request);
 }
return this.successPage(null,request);
}

saveHospital 方法

@Override
public boolean saveHospital(String data) {
JSONObject jsonObject = JSONObject.parseObject(data);
Map<String, Object> paramMap = new HashMap<>();
paramMap.put("hoscode","10000");
paramMap.put("hosname",jsonObject.getString("hosname"))
//圖片
paramMap.put("logoData", jsonObject.getString("logoData"));
// http://localhost:8201/api/hosp/saveHospital
//httpclient
JSONObject respone =
HttpRequestHelper.sendRequest(paramMap,this.getApiUrl()+"/api/hosp/saveHospital");
System.out.println(respone.toJSONString());
if(null != respone && 200 == respone.getIntValue("code")) {
returntrue;
else {
throw new YyghException(respone.getString("message"), 201);
}
}

HttpRequestHelper 工具類

/**
 * 封裝同步請求
 * @param paramMap
 * @param url
 * @return
 */
public static JSONObject sendRequest(Map<String, Object> paramMap, String url){
String result = "";
try {
//封裝post參數
StringBuilder postdata = new StringBuilder();
for (Map.Entry<String, Object> param : paramMap.entrySet()) {
postdata.append(param.getKey()).append("=")
.append(param.getValue()).append("&");
}
log.info(String.format("--> 發送請求:post data %1s", postdata));
byte[] reqData = postdata.toString().getBytes("utf-8");
byte[] respdata = HttpUtil.doPost(url,reqData);
result = new String(respdata);
log.info(String.format("--> 應答結果:result data %1s", result));
} catch (Exception ex) {
ex.printStackTrace();
}
return JSONObject.parseObject(result);
}

HttpUtil 工具類

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.setUseCaches(false);
httpcon.setInstanceFollowRedirects(true);
httpcon.setConnectTimeout(CONN_TIMEOUT);
httpcon.setReadTimeout(READ_TIMEOUT);
httpcon.setRequestMethod(reqmethod);
httpcon.connect();
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"));
String inputLine;
StringBuilder bankXmlBuffer = new StringBuilder();
while ((inputLine = in.readLine()) != null) {
bankXmlBuffer.append(inputLine);
}
in.close();
httpcon.disconnect();
return bankXmlBuffer.toString().getBytes();
} catch (Exception ex) {
log.error(ex.toString(), ex);
return null;
}
 }

對應平台介面

@RestController
@RequestMapping("/api/hosp")
public class ApiController {
@Autowired
private HospitalService hospitalService;
@ApiOperation(value = "上傳醫院")
@PostMapping("saveHospital")
public R saveHospital(HttpServletRequest request) {
//透過request取到前端介面傳過來的值
Map<String, String[]> parameterMap = request.getParameterMap();
//將陣列值轉換成一個值
Map<String, Object> paramMap = HttpRequestHelper.switchMap(parameterMap);
//將map集合轉成josn字串
String mapStr = JSONObject.toJSONString(paramMap);
//josn字串轉成物件
Hospital hospital = JSONObject.parseObject(mapStr, Hospital. class);
//加入MongoDB中
hospitalService.saveHosp(hospital);
return R.ok();
}
}

即可完成不同系統中的相互呼叫。

來源:blog.csdn.net/weixin_52210557/article/details/122803085

END


看完本文有收獲?請轉發分享給更多人

關註「Java編程鴨」,提升Java技能

關註Java編程鴨微信公眾號,後台回復:碼農大禮包可以獲取最新整理的技術資料一份。涵蓋Java 框架學習、架構師學習等

文章有幫助的話,在看,轉發吧。

謝謝支持喲 (*^__^*)