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

Java
327
0
0
2023-06-18
标签   跨域请求

为什么会有跨域问题

常见的跨域解决方式

1.在控制层加入允许跨域的注解 @CrossOrigin
2.使用 HttpClient ,不依赖浏览器
3.使用网关 getway

注解:@CrossOrigin

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

网关整合

Spring Cloud Gateway作为 Spring Cloud生态系统中的网关,目标是替代Netflix Zuul,其 不仅提供统一的路由方式,并且还基于Filer链的方式提供了网关基本的功能,例如:安全、监 控/埋点、限流等。
(1)路由。路由是网关最基础的部分,路由信息有一个ID、一个目的URL、一组断言和一组 Filter组成。如果断言路由为真,则说明请求的URL和配置匹配
(2)断言。Java8中的断言函数。Spring Cloud Gateway中的断言函数输入类型是Spring5.0框 架中的 Server WebExchange。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.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=
# 服务名
spring.application.name=service-gateway
# nacos服务地址 默认
spring.cloud.nacos.discovery.server-addr= 127.0.0.1 :8888
#使用服务发现路由
spring.cloud.gateway.discovery.locator.enabled=true
#设置路由id
spring.cloud.gateway.routes[].id=service-hosp
#设置路由的uri  lb负载均衡
spring.cloud.gateway.routes[].uri=lb://service-hosp
#设置路由断言,代理servicerId为auth-service的/auth/路径
spring.cloud.gateway.routes[].predicates= Path=/*/hosp/**

#设置路由id
spring.cloud.gateway.routes[].id=service-cmn
#设置路由的uri
spring.cloud.gateway.routes[].uri=lb://service-cmn
#设置路由断言,代理servicerId为auth-service的/auth/路径
spring.cloud.gateway.routes[].predicates= Path=/*/cmn/**
#设置路由id
spring.cloud.gateway.routes[].id=service-hosp
#设置路由的uri
spring.cloud.gateway.routes[].uri=lb://service-hosp
#设置路由断言,代理servicerId为auth-service的/auth/路径
spring.cloud.gateway.routes[].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.addAllowed Header ("*");

        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(new PathPatternParser());
        source.registerCorsConfiguration("/**", config);

        return new CorsWebFilter(source);
    }
}

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

Httpclient

常见的使用场景: 多系统 之间接口的交互、 爬虫

http原生请求,获取 百度 首页代码

 public class HttpTest {
    @Test
    public void test() throws  Exception  {
     String url = "#;;
        URL url = new URL(url);
        //url连接
        URLConnection urlConnection = url.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-");

使用HttpClient发送请求、接收响应

1. 创建HttpClient对象。
2. 创建请求方法的实例,并指定请求URL。如果需要发送GET请求,创建HttpGet对象;
如果需要发送POST请求,创建HttpPost对象。
3. 如果需要发送请求参数,可调用HttpGet、HttpPost共同的set params (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>.5.13</version>
</dependency>
  @Test
    public void test(){
        //可关闭的httpclient客户端,相当于打开一个浏览器
        CloseableHttpClient client = HttpClients.createDefault();
        String url = "#;;
        //构造httpGet请求对象
        HttpGet httpGet = new HttpGet(url);
        //响应
        CloseableHttpResponse response = null;
        try {
            response = client.execute(httpGet);
            // 获取内容
            String result = EntityUtils.toString(response.getEntity(), "utf-");
            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) {
         json Object  JSON Object = JSONObject.parseObject(data);
        Map<String, Object> paramMap = new HashMap<>();
        paramMap.put("hoscode","");
        paramMap.put("hosname",jsonObject.getString("hosname"))
        //图片
        paramMap.put("logoData", jsonObject.getString("logoData"));
        //  
        //httpclient
        JSONObject respone =
                HttpRequestHelper.sendRequest(paramMap,this.getApiUrl()+"/api/hosp/saveHospital");
        System.out.println(respone.toJSONString());

        if(null != respone && == respone.getIntValue("code")) {
            return true;
        } else {
            throw new YyghException(respone.getString("message"),);
        }
    }

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 %s", postdata));
             byte [] reqData = postdata.toString().getBytes("utf-8");
            byte[] respdata = HttpUtil.doPost(url,reqData);
            result = new String(respdata);
            log.info(String.format("--> 应答结果:result data %s", 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-"));
   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