0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

三種跨域解決方案:HttpClient、注解、網(wǎng)關(guān)

jf_ro2CN3Fa ? 來源:CSDN技術(shù)社區(qū) ? 作者:遠走與夢游 ? 2022-11-09 17:23 ? 次閱讀

為什么會有跨域問題

因為瀏覽器的同源政策,就會產(chǎn)生跨域。比如說發(fā)送的異步請求是不同的兩個源,就比如是不同的的兩個端口或者不同的兩個協(xié)議或者不同的域名。由于瀏覽器為了安全考慮,就會產(chǎn)生一個同源政策,不是同一個地方出來的是不允許進行交互的。

常見的跨域解決方式

在控制層加入允許跨域的注解 @CrossOrigin

使用httpclient,不依賴瀏覽器

使用網(wǎng)關(guān) Gateway

注解:@CrossOrigin

在控制層加入允許跨域的注解,即可完成一個項目中前后端口跨域的問題

基于 Spring Boot + MyBatis Plus + Vue & Element 實現(xiàn)的后臺管理系統(tǒng) + 用戶小程序,支持 RBAC 動態(tài)權(quán)限、多租戶、數(shù)據(jù)權(quán)限、工作流、三方登錄、支付、短信、商城等功能

網(wǎng)關(guān)整合

Spring Cloud Gateway作為Spring Cloud生態(tài)系統(tǒng)中的網(wǎng)關(guān),目標(biāo)是替代Netflix Zuul,其 不僅提供統(tǒng)一的路由方式,并且還基于Filer鏈的方式提供了網(wǎng)關(guān)基本的功能,例如:安全、監(jiān) 控/埋點、限流等。

(1)路由

路由是網(wǎng)關(guān)最基礎(chǔ)的部分,路由信息有一個ID、一個目的URL、一組斷言和一組 Filter組成。如果斷言路由為真,則說明請求的URL和配置匹配

(2)斷言

Java8中的斷言函數(shù)。Spring Cloud Gateway中的斷言函數(shù)輸入類型是Spring5.0框 架中的ServerWebExchange。Spring Cloud Gateway中的斷言函數(shù)允許開發(fā)者去定義匹配來自 于http request中的任何信息,比如請求頭和參數(shù)等。

(3)過濾器

一個標(biāo)準(zhǔn)的Spring webFilter。Spring cloud gateway中的filter分為兩種類型的 Filter,分別是Gateway Filter和Global Filter。過濾器Filter將會對請求和響應(yīng)進行修改處理

496f0014-50e9-11ed-a3b6-dac502259ad0.png

Spring cloud Gateway發(fā)出請求。然后再由Gateway Handler Mapping中找到與請 求相匹配的路由,將其發(fā)送到Gateway web handler。Handler再通過指定的過濾器鏈將請求發(fā) 送到實際的服務(wù)執(zhí)行業(yè)務(wù)邏輯,然后返回。

項目中使用

新建模塊service_gateway


 

com.lzq
service_utils
0.0.1-SNAPSHOT


org.springframework.cloud
spring-cloud-starter-gateway

 

com.alibaba.cloud
spring-cloud-starter-alibaba-nacos-discovery


配置文件

#服務(wù)端口
server.port=9090

> 基于 Spring Cloud Alibaba + Gateway + Nacos + RocketMQ + Vue & Element 實現(xiàn)的后臺管理系統(tǒng) + 用戶小程序,支持 RBAC 動態(tài)權(quán)限、多租戶、數(shù)據(jù)權(quán)限、工作流、三方登錄、支付、短信、商城等功能
>
> * 項目地址:
> * 視頻教程

# 服務(wù)名
spring.application.name=service-gateway
# nacos服務(wù)地址 默認8848
spring.cloud.nacos.discovery.server-addr=127.0.0.1:8888
#使用服務(wù)發(fā)現(xiàn)路由
spring.cloud.gateway.discovery.locator.enabled=true
#設(shè)置路由id
spring.cloud.gateway.routes[0].id=service-hosp
#設(shè)置路由的uri  lb負載均衡
spring.cloud.gateway.routes[0].uri=lb://service-hosp
#設(shè)置路由斷言,代理servicerId為auth-service的/auth/路徑
spring.cloud.gateway.routes[0].predicates= Path=/*/hosp/**
 
#設(shè)置路由id
spring.cloud.gateway.routes[1].id=service-cmn
#設(shè)置路由的uri
spring.cloud.gateway.routes[1].uri=lb://service-cmn
#設(shè)置路由斷言,代理servicerId為auth-service的/auth/路徑
spring.cloud.gateway.routes[1].predicates= Path=/*/cmn/**
#設(shè)置路由id
spring.cloud.gateway.routes[2].id=service-hosp
#設(shè)置路由的uri
spring.cloud.gateway.routes[2].uri=lb://service-hosp
#設(shè)置路由斷言,代理servicerId為auth-service的/auth/路徑
spring.cloud.gateway.routes[2].predicates= Path=/*/userlogin/**

創(chuàng)建啟動類

@SpringBootApplication
publicclassApiGatewayApplication{
publicstaticvoidmain(String[]args){
SpringApplication.run(ApiGatewayApplication.class,args);
}
}

修改前端.evn文件,改成訪問網(wǎng)關(guān)端口號

做集群部署時,他會根據(jù)名稱實現(xiàn)負載均衡

跨域理解:發(fā)送請求后,網(wǎng)關(guān)過濾器會進行請求攔截,將跨域放行,轉(zhuǎn)發(fā)到服務(wù)器中

跨域配置類

@Configuration
publicclassCorsConfig{
@Bean
publicCorsWebFiltercorsFilter(){
CorsConfigurationconfig=newCorsConfiguration();
config.addAllowedMethod("*");
config.addAllowedOrigin("*");
config.addAllowedHeader("*");

UrlBasedCorsConfigurationSourcesource=newUrlBasedCorsConfigurationSource(newPathPatternParser());
source.registerCorsConfiguration("/**",config);

returnnewCorsWebFilter(source);
}
}

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

Httpclient

常見的使用場景:多系統(tǒng)之間接口的交互、爬蟲

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

publicclassHttpTest{
@Test
publicvoidtest1()throwsException{
Stringurl="https://www.badu.com";
URLurl1=newURL(url);
//url連接
URLConnectionurlConnection=url1.openConnection();
HttpURLConnectionhttpURLConnection=(HttpURLConnection)urlConnection;
//獲取httpURLConnection輸入流
InputStreamis=httpURLConnection.getInputStream();
//轉(zhuǎn)換為字符串
InputStreamReaderreader=newInputStreamReader(is,StandardCharsets.UTF_8);
BufferedReaderbr=newBufferedReader(reader);
Stringline;
//將字符串一行一行讀取出來
while((line=br.readLine())!=null){
System.out.println(line);
}
}
}
//設(shè)置請求類型
httpURLConnection.setRequestMethod("GET");
//請求包含請求行、空格、請求頭、請求體
//設(shè)置請求頭編碼
httpURLConnection.setRequestProperty("Accept-Charset","utf-8");

使用HttpClient發(fā)送請求、接收響應(yīng)

創(chuàng)建HttpClient對象。

創(chuàng)建請求方法的實例,并指定請求URL。如果需要發(fā)送GET請求,創(chuàng)建HttpGet對象;如果需要發(fā)送POST請求,創(chuàng)建HttpPost對象。

如果需要發(fā)送請求參數(shù),可調(diào)用HttpGet、HttpPost共同的setParams(HetpParams params)方法來添加請求參數(shù);對于HttpPost對象而言,也可調(diào)用setEntity(HttpEntity entity)方法來設(shè)置請求參數(shù)。

調(diào)用HttpClient對象的execute(HttpUriRequest request)發(fā)送請求,該方法返回一個HttpResponse。

調(diào)用HttpResponse的getAllHeaders()、getHeaders(String name)等方法可獲取服務(wù)器的響應(yīng)頭;調(diào)用HttpResponse的getEntity()方法可獲取HttpEntity對象,該對象包裝了服務(wù)器的響應(yīng)內(nèi)容。程序可通過該對象獲取服務(wù)器的響應(yīng)內(nèi)容。

釋放連接。無論執(zhí)行方法是否成功,都必須釋放連接

集成測試,添加依賴


org.apache.httpcomponents
httpclient
4.5.13

@Test
publicvoidtest2(){
//可關(guān)閉的httpclient客戶端,相當(dāng)于打開一個瀏覽器
CloseableHttpClientclient=HttpClients.createDefault();
Stringurl="https://www.baidu.com";
//構(gòu)造httpGet請求對象
HttpGethttpGet=newHttpGet(url);
//響應(yīng)
CloseableHttpResponseresponse=null;
try{
response=client.execute(httpGet);
//獲取內(nèi)容
Stringresult=EntityUtils.toString(response.getEntity(),"utf-8");
System.out.println(result);
}catch(Exceptione){
e.printStackTrace();
}finally{
//關(guān)閉流
if(client!=null){
try{
client.close();
}catch(IOExceptione){
e.printStackTrace();
}
}
}
}

項目中使用,系統(tǒng)調(diào)用平臺接口保存信息,根據(jù)傳入josn數(shù)據(jù)保存信息

系統(tǒng)中

@RequestMapping(value="/hospital/save",method=RequestMethod.POST)
publicStringsaveHospital(Stringdata,HttpServletRequestrequest){
try{
apiService.saveHospital(data);
}catch(YyghExceptione){
returnthis.failurePage(e.getMessage(),request);
}catch(Exceptione){
returnthis.failurePage("數(shù)據(jù)異常",request);
}
returnthis.successPage(null,request);
}

saveHospital方法

@Override
publicbooleansaveHospital(Stringdata){
JSONObjectjsonObject=JSONObject.parseObject(data);
MapparamMap=newHashMap<>();
paramMap.put("hoscode","10000");
paramMap.put("hosname",jsonObject.getString("hosname"))
//圖片
paramMap.put("logoData",jsonObject.getString("logoData"));
//http://localhost:8201/api/hosp/saveHospital
//httpclient
JSONObjectrespone=
HttpRequestHelper.sendRequest(paramMap,this.getApiUrl()+"/api/hosp/saveHospital");
System.out.println(respone.toJSONString());

if(null!=respone&&200==respone.getIntValue("code")){
returntrue;
}else{
thrownewYyghException(respone.getString("message"),201);
}
}

HttpRequestHelper工具類

/**
*封裝同步請求
*@paramparamMap
*@paramurl
*@return
*/
publicstaticJSONObjectsendRequest(MapparamMap,Stringurl){
Stringresult="";
try{
//封裝post參數(shù)
StringBuilderpostdata=newStringBuilder();
for(Map.Entryparam:paramMap.entrySet()){
postdata.append(param.getKey()).append("=")
.append(param.getValue()).append("&");
}
log.info(String.format("-->發(fā)送請求:postdata%1s",postdata));
byte[]reqData=postdata.toString().getBytes("utf-8");
byte[]respdata=HttpUtil.doPost(url,reqData);
result=newString(respdata);
log.info(String.format("-->應(yīng)答結(jié)果:resultdata%1s",result));
}catch(Exceptionex){
ex.printStackTrace();
}
returnJSONObject.parseObject(result);
}

HttpUtil工具類

publicstaticbyte[]send(StringstrUrl,Stringreqmethod,byte[]reqData){
try{
URLurl=newURL(strUrl);
HttpURLConnectionhttpcon=(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)){
OutputStreamos=httpcon.getOutputStream();
os.write(reqData);
os.flush();
os.close();
}
BufferedReaderin=newBufferedReader(newInputStreamReader(httpcon.getInputStream(),"utf-8"));
StringinputLine;
StringBuilderbankXmlBuffer=newStringBuilder();
while((inputLine=in.readLine())!=null){
bankXmlBuffer.append(inputLine);
}
in.close();
httpcon.disconnect();
returnbankXmlBuffer.toString().getBytes();
}catch(Exceptionex){
log.error(ex.toString(),ex);
returnnull;
}
}

對應(yīng)平臺接口

@RestController
@RequestMapping("/api/hosp")
publicclassApiController{
@Autowired
privateHospitalServicehospitalService;
@ApiOperation(value="上傳醫(yī)院")
@PostMapping("saveHospital")
publicRsaveHospital(HttpServletRequestrequest){
//通過request取到前端接口傳過來的值
MapparameterMap=request.getParameterMap();
//將數(shù)組值轉(zhuǎn)換成一個值
MapparamMap=HttpRequestHelper.switchMap(parameterMap);
//將map集合轉(zhuǎn)成josn字符串
StringmapStr=JSONObject.toJSONString(paramMap);
//josn字符串轉(zhuǎn)成對象
Hospitalhospital=JSONObject.parseObject(mapStr,Hospital.class);
//加入MongoDB中
hospitalService.saveHosp(hospital);
returnR.ok();
}
}

即可完成不同系統(tǒng)中的相互調(diào)用

審核編輯:湯梓紅

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • 瀏覽器
    +關(guān)注

    關(guān)注

    1

    文章

    1007

    瀏覽量

    35178
  • spring
    +關(guān)注

    關(guān)注

    0

    文章

    335

    瀏覽量

    14278
  • httpclient
    +關(guān)注

    關(guān)注

    0

    文章

    3

    瀏覽量

    1843

原文標(biāo)題:三種跨域解決方案:HttpClient、注解、網(wǎng)關(guān)

文章出處:【微信號:芋道源碼,微信公眾號:芋道源碼】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。

收藏 人收藏

    評論

    相關(guān)推薦

    FPGA設(shè)計中解決時鐘方案

    介紹3時鐘處理的方法,這3方法可以說是FPGA界最常用也最實用的方法,這三種方法包含了單bit和多bit數(shù)據(jù)的
    的頭像 發(fā)表于 11-21 11:13 ?3790次閱讀
    FPGA設(shè)計中解決<b class='flag-5'>跨</b>時鐘<b class='flag-5'>域</b>的<b class='flag-5'>三</b>大<b class='flag-5'>方案</b>

    時鐘解決方案

    在很久之前便陸續(xù)談過亞穩(wěn)態(tài),F(xiàn)IFO,復(fù)位的設(shè)計。本次亦安做一個簡單的總結(jié),從宏觀上給大家展示時鐘解決方案。
    的頭像 發(fā)表于 01-08 09:42 ?805次閱讀
    <b class='flag-5'>跨</b>時鐘<b class='flag-5'>域</b>的<b class='flag-5'>解決方案</b>

    如何處理好FPGA設(shè)計中時鐘問題?

    時鐘處理是 FPGA 設(shè)計中經(jīng)常遇到的問題,而如何處理好時鐘間的數(shù)據(jù),可以說是每個 FPGA 初學(xué)者的必修課。如果是還在校生,時鐘
    發(fā)表于 09-22 10:24

    探尋FPGA中三種時鐘處理方法

    時鐘處理是 FPGA 設(shè)計中經(jīng)常遇到的問題,而如何處理好時鐘間的數(shù)據(jù),可以說是每個 FPGA 初學(xué)者的必修課。如果是還在校生,時鐘
    發(fā)表于 10-20 09:27

    三種時鐘處理的方法

      時鐘處理是FPGA設(shè)計中經(jīng)常遇到的問題,而如何處理好時鐘間的數(shù)據(jù),可以說是每個FPGA初學(xué)者的必修課。如果是還在校生,時鐘
    發(fā)表于 01-08 16:55

    三種FPGA界最常用的時鐘處理法式

    時鐘處理是FPGA設(shè)計中經(jīng)常遇到的問題,而如何處理好時鐘間的數(shù)據(jù),可以說是每個FPGA初學(xué)者的必修課。如果是還在校生,時鐘
    發(fā)表于 02-21 07:00

    如何處理好FPGA設(shè)計中時鐘間的數(shù)據(jù)

    介紹3時鐘處理的方法,這3方法可以說是FPGA界最常用也最實用的方法,這三種方法包含了單bit和多bit數(shù)據(jù)的
    發(fā)表于 07-29 06:19

    三種電源方案

    三種電源方案   電源+充電線路方案               &
    發(fā)表于 11-13 15:05 ?1087次閱讀

    三種3D眼鏡解決方案

    介紹了三種3D眼鏡解決方案,MSP430方案,TPS65835方案,射頻穿梭3D電視眼鏡。
    發(fā)表于 09-14 10:23 ?35次下載
    <b class='flag-5'>三種</b>3D眼鏡<b class='flag-5'>解決方案</b>

    三種pads解決方案的對比

    三種解決方案交付核心能力來加速你的設(shè)計周期,提高生產(chǎn)率,提高質(zhì)量。了解每個解決方案當(dāng)你開始你的比較過程。
    的頭像 發(fā)表于 10-30 07:06 ?3410次閱讀

    揭秘FPGA時鐘處理的大方法

    時鐘處理是 FPGA 設(shè)計中經(jīng)常遇到的問題,而如何處理好時鐘間的數(shù)據(jù),可以說是每個 FPGA 初學(xué)者的必修課。如果是還在校生,時鐘
    的頭像 發(fā)表于 12-05 16:41 ?1574次閱讀

    介紹3方法時鐘處理方法

    介紹3時鐘處理的方法,這3方法可以說是FPGA界最常用也最實用的方法,這三種方法包含了單bit和多bit數(shù)據(jù)的
    的頭像 發(fā)表于 09-18 11:33 ?2.2w次閱讀
    介紹3<b class='flag-5'>種</b>方法<b class='flag-5'>跨</b>時鐘<b class='flag-5'>域</b>處理方法

    三種時鐘處理的方法

    時鐘處理是FPGA設(shè)計中經(jīng)常遇到的問題,而如何處理好時鐘間的數(shù)據(jù),可以說是每個FPGA初學(xué)者的必修課。如果是還在校生,時鐘
    的頭像 發(fā)表于 10-18 09:12 ?7367次閱讀

    刺激能量收集發(fā)展的三種解決方案

    新技術(shù)星期二:刺激能量收集發(fā)展的三種解決方案
    的頭像 發(fā)表于 12-30 09:40 ?530次閱讀

    菱M70 PLC增加注解三種方法簡析

    菱M70 PLC增加注解三種方法
    的頭像 發(fā)表于 02-26 09:59 ?980次閱讀
    <b class='flag-5'>三</b>菱M70 PLC增加<b class='flag-5'>注解</b>的<b class='flag-5'>三種</b>方法簡析