使用SpringCloudApiGateway之支持Cors跨域请求

作者:Moshow郑锴 时间:2022-10-15 18:28:08 

问题背景

公司的项目需要前后端分离,vue+java,这时候就需要支持Cors跨域请求了。最近对zuul进行升级,假如说zuul是1.0的话,api gateway就是2.0的网关,支持ws等,基于NIO,各方面还是强大的。

解决方案

新建一个Configuration类即可


import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.cloud.gateway.discovery.DiscoveryClientRouteDefinitionLocator;
import org.springframework.cloud.gateway.route.RouteDefinitionLocator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.web.cors.reactive.CorsUtils;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebFilter;
import org.springframework.web.server.WebFilterChain;
import reactor.core.publisher.Mono;
/**
* SpringApiGateway Cors
*/
@Configuration
public class RouteConfiguration {
   //这里为支持的请求头,如果有自定义的header字段请自己添加(不知道为什么不能使用*)
   private static final String ALLOWED_HEADERS = "x-requested-with, authorization, Content-Type, Authorization, credential, X-XSRF-TOKEN,token,username,client";
   private static final String ALLOWED_METHODS = "*";
   private static final String ALLOWED_ORIGIN = "*";
   private static final String ALLOWED_Expose = "x-requested-with, authorization, Content-Type, Authorization, credential, X-XSRF-TOKEN,token,username,client";
   private static final String MAX_AGE = "18000L";
   @Bean
   public WebFilter corsFilter() {
       return (ServerWebExchange ctx, WebFilterChain chain) -> {
           ServerHttpRequest request = ctx.getRequest();
           if (CorsUtils.isCorsRequest(request)) {
               ServerHttpResponse response = ctx.getResponse();
               HttpHeaders headers = response.getHeaders();
               headers.add("Access-Control-Allow-Origin", ALLOWED_ORIGIN);
               headers.add("Access-Control-Allow-Methods", ALLOWED_METHODS);
               headers.add("Access-Control-Max-Age", MAX_AGE);
               headers.add("Access-Control-Allow-Headers", ALLOWED_HEADERS);
               headers.add("Access-Control-Expose-Headers", ALLOWED_Expose);
               headers.add("Access-Control-Allow-Credentials", "true");
               if (request.getMethod() == HttpMethod.OPTIONS) {
                   response.setStatusCode(HttpStatus.OK);
                   return Mono.empty();
               }
           }
           return chain.filter(ctx);
       };
   }
   /**
   *
   *如果使用了注册中心(如:Eureka),进行控制则需要增加如下配置
   */
   @Bean
   public RouteDefinitionLocator discoveryClientRouteDefinitionLocator(DiscoveryClient discoveryClient) {
       return new DiscoveryClientRouteDefinitionLocator(discoveryClient);
   }
}

application.yml配置

官方文档提及到还有另外一种方式,就是通过yml来配置。


spring:
 cloud:
   gateway:
     globalcors:
       corsConfigurations:
         '[/**]':
           allowedOrigins: "https://blog.csdn.net/moshowgame"
           allowedMethods:
           - GET

跨域解决方案(CORS)

1. 什么是跨域?

跨域问题是出于浏览器的【同源策略】限制。同源策略(Sameoriginpolicy)是一种约定,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,则浏览器的正常功能可能都会受到影响。

可以说Web是构建在同源策略基础之上的,浏览器只是针对同源策略的一种实现。同源策略会阻止一个域的javascript脚本和另外一个域的内容进行交互。

所谓同源(即指在同一个域)就是两个页面具有相同的协议(protocol),主机(host)和端口号(port)

由于我们现在是采用的前后端分离的微服务架构,前端和后端必定存在跨域问题。解决跨域问题可以采用CORS。

2. CORS简介

CORS 是一个 W3C 标准,全称是"跨域资源共享"(Cross-origin resource sharing)。

CORS需要浏览器和服务器同时支持。但是目前基本上浏览器都支持,所以我们只要保证服务器端服务器实现了 CORS 接口,就可以跨源通信。

浏览器将CORS请求分成两类:简单请求(simple request)和非简单请求(not-so-simple request)。

3. 具体解决方式

解决跨域问题,就是在服务器端给响应添加头信息

NameRequiredComments
Access-Control-Allow-Origin必填允许请求的域
Access-Control-Allow-Methods必填允许请求的方法
Access-Control-Allow-Headers可选预检请求后,告知发送请求需要有的头部
Access-Control-Allow-Credentials可选表示是否允许发送cookie,默认false;
Access-Control-Max-Age可选本次预检的有效期,单位:秒;

3.1 在Spring Boot 中解决

在spring boot中给我们提供了 @CrossOrigin 注解用于解决跨域问题。

使用场景要求:jdk1.8+、Spring4.2+

只需要在我们需要的controller上加@CrossOrigin


@RestController
//实现跨域注解
//origin="*"代表所有域名都可访问
//maxAge飞行前响应的缓存持续时间的最大年龄,简单来说就是Cookie的有效期 单位为秒若maxAge是负数,则代表为临时Cookie,不会被持久化,Cookie信息保存在浏览器内存中,浏览器关闭Cookie就消失
@CrossOrigin(origins = "*",maxAge = 3600)
@RequestMapping("/album")
public class AlbumController {}

3.2 在spring Cloud中解决

只需要在spring Cloud Gateway 服务中添加配置就行


spring:
 application:
   name: system-gateway
 cloud:
   gateway:
     globalcors:
       cors-configurations:
         '[/**]': # 匹配所有请求
           allowedOrigins: "*" #跨域处理 允许所有的域
           allowedMethods: # 支持的方法
           - GET
           - POST
           - PUT
           - DELETE

当然也可以自己利用Gateway的 * 来手动添加相应的头信息


default-filters:
     - AddResponseHeader=Access-Control-Allow-Credentials,true
     - AddResponseHeader=Access-Control-Allow-Headers,access-control-allow-origin
     - AddResponseHeader=Access-Control-Allow-Methods,GET
     - AddResponseHeader=Access-Control-Allow-Origin,*
     - AddResponseHeader=Access-Control-Allow-Age,3600

3.3 在Nginx中解决


location /example {
  if ($request_method = 'OPTIONS') {
      add_header Access-Control-Allow-Origin *;
      add_header Access-Control-Max-Age 1728000;
      add_header Access-Control-Allow-Methods GET,POST,OPTIONS;
      add_header Access-Control-Allow-Headers  'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
      add_header Content-Type' 'text/plain; charset=utf-8';
      add_header Content-Length 0 ;
      return 204;
   }

+   if ($http_origin ~* (https?://(.+\.)?(example\.com$))) {
+     add_header  Access-Control-Allow-Origin $http_origin;
+     add_header  Access-Control-Allow-Credentials true;
+     add_header  Access-Control-Allow-Methods GET,POST,OPTIONS;
+     add_header  Access-Control-Expose-Headers Content-Length,Content-Range;
+   }

proxy_redirect off;
   proxy_set_header Host $host;
   proxy_set_header X-Real-IP $remote_addr;
   proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
   proxy_pass http://127.0.0.1:8080/;
  }

解释:

if ($request_method = 'OPTIONS') {...} 当请求方法为 OPTIONS 时:

  1. 添加允许源 Access-Control-Allow-Origin 为 * (可根据业务需要更改)

  2. 添加缓存时长 Access-Control-Max-Age,当下次请求时,无需再发送 OPTIONS 请求

  3. 添加允许的方法,允许的首部

  4. 添加一个内容长度为0,类型为 text/plain; charset=utf-8 , 返回状态码为 204 的首部

if ($http_origin ~* (https?://(.+\.)?(example\.com$))) {...}, 当 origin 为合法域名(可根据业务调整或去除合法域名验证)时:

  1. 添加允许源Access-Control-Allow-Origin为 $http_origin (可根据业务需要更改)

  2. 添加允许认证Access-Control-Allow-Credentials为 true ,允许接收客户端 Cookie(可根据业务需要更改。 但要注意,当设置为true时,Access-Control-Allow-Origin 不允许设置为 *)

  3. 添加允许的方法,暴露的首部

至此,完成跨域请求正确响应。

以上,是对跨域请求在Web Server的解决方案,主要是通过响应 OPTIONS 方法和添加允许源来解决。希望能给大家一个参考,也希望大家多多支持脚本之家

来源:https://zhengkai.blog.csdn.net/article/details/84618781

标签:Gateway,Cors,跨域请求
0
投稿

猜你喜欢

  • Java聊天室之使用Socket实现通信功能

    2022-03-08 09:46:27
  • Java shiro安全框架使用介绍

    2023-07-09 05:24:35
  • 浅谈Java日志框架slf4j作用及其实现原理

    2022-11-02 19:02:04
  • java如何获得redis所有的key-value

    2022-03-13 12:22:14
  • Java使用BIO和NIO进行文件操作对比代码示例

    2023-04-18 16:14:21
  • Mybatis配置之typeAlias标签的用法

    2023-11-27 20:18:20
  • 一篇超详细的SpringBoot整合MybatisPlus的文章

    2023-02-26 11:04:35
  • SpringBoot 如何实时刷新静态文件

    2023-11-02 13:27:09
  • Java构造代码块,静态代码块原理与用法实例分析

    2023-11-03 09:03:45
  • C#实现对象XML序列化的方法

    2022-02-11 01:30:59
  • 详解Java七大阻塞队列之SynchronousQueue

    2023-12-16 04:21:30
  • C#将HashTable中键列表或值列表复制到一维数组的方法

    2022-01-05 22:12:12
  • Android编程设置屏幕亮度的方法

    2022-07-02 16:40:52
  • Spring Boot打war包的实例教程

    2022-10-05 07:52:49
  • 基于SqlSessionFactory的openSession方法使用

    2023-02-26 23:10:15
  • 在Java中使用redisTemplate操作缓存的方法示例

    2023-07-04 09:03:28
  • 线程局部变量的实现 ThreadLocal使用及场景介绍

    2023-11-10 03:19:26
  • 深入探索Java常量池

    2022-12-28 00:55:53
  • Idea jdk版本问题解决方案

    2022-04-14 11:57:41
  • Android Handler主线程和一般线程通信的应用分析

    2022-10-29 14:08:13
  • asp之家 软件编程 m.aspxhome.com