三种跨域解决方案:HttpClient、注解、网关

电子说

1.3w人已加入

描述

为什么会有跨域问题

因为浏览器的同源政策,就会产生跨域。比如说发送的异步请求是不同的两个源,就比如是不同的的两个端口或者不同的两个协议或者不同的域名。由于浏览器为了安全考虑,就会产生一个同源政策,不是同一个地方出来的是不允许进行交互的。

常见的跨域解决方式

在控制层加入允许跨域的注解 @CrossOrigin

使用httpclient,不依赖浏览器

使用网关 Gateway

注解:@CrossOrigin

在控制层加入允许跨域的注解,即可完成一个项目中前后端口跨域的问题

基于 Spring Boot + MyBatis Plus + Vue & Element 实现的后台管理系统 + 用户小程序,支持 RBAC 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能

网关整合

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将会对请求和响应进行修改处理

httpclient

Spring cloud Gateway发出请求。然后再由Gateway Handler Mapping中找到与请 求相匹配的路由,将其发送到Gateway web handler。Handler再通过指定的过滤器链将请求发 送到实际的服务执行业务逻辑,然后返回。

项目中使用

新建模块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
    

 

配置文件

 

#服务端口
server.port=9090

> 基于 Spring Cloud Alibaba + Gateway + Nacos + RocketMQ + Vue & Element 实现的后台管理系统 + 用户小程序,支持 RBAC 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能
>
> * 项目地址:
> * 视频教程:

# 服务名
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发送请求、接收响应

创建HttpClient对象。

创建请求方法的实例,并指定请求URL。如果需要发送GET请求,创建HttpGet对象;如果需要发送POST请求,创建HttpPost对象。

如果需要发送请求参数,可调用HttpGet、HttpPost共同的setParams(HetpParams params)方法来添加请求参数;对于HttpPost对象而言,也可调用setEntity(HttpEntity entity)方法来设置请求参数。

调用HttpClient对象的execute(HttpUriRequest request)发送请求,该方法返回一个HttpResponse。

调用HttpResponse的getAllHeaders()、getHeaders(String name)等方法可获取服务器的响应头;调用HttpResponse的getEntity()方法可获取HttpEntity对象,该对象包装了服务器的响应内容。程序可通过该对象获取服务器的响应内容。

释放连接。无论执行方法是否成功,都必须释放连接

集成测试,添加依赖

 


    org.apache.httpcomponents
    httpclient
    4.5.13

@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 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")) {
        return true;
    } else {
        throw new YyghException(respone.getString("message"), 201);
    }
}

 

HttpRequestHelper工具类

 

/**
 * 封装同步请求
 * @param paramMap
 * @param url
 * @return
 */
public static JSONObject sendRequest(Map paramMap, String url){
    String result = "";
    try {
        //封装post参数
        StringBuilder postdata = new StringBuilder();
        for (Map.Entry 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 parameterMap = request.getParameterMap();
        //将数组值转换成一个值
        Map 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();
    }
}

 

即可完成不同系统中的相互调用

  审核编辑:汤梓红

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分