5.跨域处理

简介: 本文介绍了跨域问题的产生原因及解决方案。当协议、域名或端口不同时,浏览器因同源策略阻止资源访问。通过CORS(跨域资源共享)机制,使用`@CrossOrigin`注解、全局配置`WebMvcConfigurer`或自定义过滤器添加响应头,可实现安全跨域。

一、跨域背景
1.1 何为跨域?
Url的一般格式:
协议 + 域名(子域名 + 主域名) + 端口号 + 资源地址
示例:
https://www.dustyblog.cn:8080/say/Hello 是由
https + www + dustyblog.cn + 8080 + say/Hello
组成。
只要协议,子域名,主域名,端口号这四项组成部分中有一项不同,就可以认为是不同的域,不同的域之间互相访问资源,就被称之为跨域。
1.2 一次正常的请求
● Controller层代码:
@RequestMapping("/demo")
@RestController
public class CorsTestController {
@GetMapping("/sayHello")
public String sayHello() {
return "hello world !";
}
}
● 启动项目,测试请求
浏览器打开localhost:8080/demo/sayHello
可以打印出“hello world”
1.3 跨域测试
以Chrome为例:
● 打开任意网站,如:https://blog.csdn.net
● 按F12,打开【开发者工具】,在里面的【Console】可以直接输入js代码测试;
var token= "LtSFVqKxvpS1nPARxS2lpUs2Q2IpGstidMrS8zMhNV3rT7RKnhLN6d2FFirkVEzVIeexgEHgI/PtnynGqjZlyGkJa4+zYIXxtDMoK/N+AB6wtsskYXereH3AR8kWErwIRvx+UOFveH3dgmdw1347SYjbL/ilGKX5xkoZCbfb1f0=,LZkg22zbNsUoHAgAUapeBn541X5OHUK7rLVNHsHWDM/BA4DCIP1f/3Bnu4GAElQU6cds/0fg9Li5cSPHe8pyhr1Ii/TNcUYxqHMf9bHyD6ugwOFTfvlmtp6RDopVrpG24RSjJbWy2kUOOjjk5uv6FUTmbrSTVoBEzAXYKZMM2m4=,R4QeD2psvrTr8tkBTjnnfUBw+YR4di+GToGjWYeR7qZk9hldUVLlZUsEEPWjtBpz+UURVmplIn5WM9Ge29ft5aS4oKDdPlIH8kWNIs9Y3r9TgH3MnSUTGrgayaNniY9Ji5wNZiZ9cE2CFzlxoyuZxOcSVfOxUw70ty0ukLVM/78=";
var xhr = new XMLHttpRequest();
xhr.open('GET', 'http://127.0.0.1:8080/demo/sayHello');
xhr.setRequestHeader("x-access-token",token);
xhr.send(null);
xhr.onload = function(e) {
var xhr = e.target;
console.log(xhr.responseText);
}
● 输入完后直接按回车键就可以返回结果:
Access to XMLHttpRequest at 'http://127.0.0.1:8080/demo/sayHello'
from origin 'https://blog.csdn.net' has been blocked by CORS policy:
No 'Access-Control-Allow-Origin' header is present on the requested resource.
该结果表明:该请求在https://blog.csdn.net域名下请求失败!
二、解决方案 - Cors跨域
2.1 Cors是什么
CORS全称为Cross Origin Resource Sharing(跨域资源共享), 每一个页面需要返回一个名为Access-Control-Allow-Origin的http头来允许外域的站点访问,你可以仅仅暴露有限的资源和有限的外域站点访问。
我们可以理解为:如果一个请求需要允许跨域访问,则需要在http头中设置Access-Control-Allow-Origin来决定需要允许哪些站点来访问。如假设需要允许https://www.dustyblog.c这个站点的请求跨域,则可以设置:
Access-Control-Allow-Origin:https://www.dustyblog.cn。
2.2 方案一:使用@CrossOrigin注解
2.2.1 在Controller上使用@CrossOrigin注解
该类下的所有接口都可以通过跨域访问
@RequestMapping("/demo2")
@RestController
//@CrossOrigin //所有域名均可访问该类下所有接口
@CrossOrigin("https://blog.csdn.net") // 只有指定域名可以访问该类下所有接口
public class CorsTest2Controller {
@GetMapping("/sayHello")
public String sayHello() {
return "hello world --- 2";
}
}
这里指定当前的CorsTest2Controller中所有的方法可以处理https://csdn.net域上的请求,这里可以测试一下:
● 在https://blog.csdn.net页面打开调试窗口,输入(注意:这里请求地址是/demo2,请区别于1.2 案例中的/demo)
var token= "LtSFVqKxvpS1nPARxS2lpUs2Q2IpGstidMrS8zMhNV3rT7RKnhLN6d2FFirkVEzVIeexgEHgI/PtnynGqjZlyGkJa4+zYIXxtDMoK/N+AB6wtsskYXereH3AR8kWErwIRvx+UOFveH3dgmdw1347SYjbL/ilGKX5xkoZCbfb1f0=,LZkg22zbNsUoHAgAUapeBn541X5OHUK7rLVNHsHWDM/BA4DCIP1f/3Bnu4GAElQU6cds/0fg9Li5cSPHe8pyhr1Ii/TNcUYxqHMf9bHyD6ugwOFTfvlmtp6RDopVrpG24RSjJbWy2kUOOjjk5uv6FUTmbrSTVoBEzAXYKZMM2m4=,R4QeD2psvrTr8tkBTjnnfUBw+YR4di+GToGjWYeR7qZk9hldUVLlZUsEEPWjtBpz+UURVmplIn5WM9Ge29ft5aS4oKDdPlIH8kWNIs9Y3r9TgH3MnSUTGrgayaNniY9Ji5wNZiZ9cE2CFzlxoyuZxOcSVfOxUw70ty0ukLVM/78=";
var xhr = new XMLHttpRequest();
xhr.open('GET', 'http://127.0.0.1:8080/demo2/sayHello');
xhr.setRequestHeader("x-access-token",token);
xhr.send(null);
xhr.onload = function(e) {
var xhr = e.target;
console.log(xhr.responseText);
}
返回结果:
ƒ (e) {
var xhr = e.target;
console.log(xhr.responseText);
}
VM156:8 hello world --- 2
说明跨域成功!
● 换个域名测试一下看跨域是否还有效,在https://www.baidu.com按照上述方法测试一下,返回结果:
OPTIONS http://127.0.0.1:8080/demo2/sayHello 403
(anonymous)
Access to XMLHttpRequest at 'http://127.0.0.1:8080/demo2/sayHello'
from origin 'http://www.cnblogs.com' has been blocked by CORS policy:
Response to preflight request doesn't pass access control check:
No 'Access-Control-Allow-Origin' header is present on the requested resource.
说明跨域失败!证明该方案成功指定了部分域名能跨域!
2.3 方案二:CORS全局配置-实现WebMvcConfigurer
● 新建跨域配置类:CorsConfig.java:
/**

  • 跨域配置
    */
    @Configuration
    public class CorsConfig implements WebMvcConfigurer {
    @Bean
    public WebMvcConfigurer corsConfigurer()
    {
     return new WebMvcConfigurer() {
         @Override
         public void addCorsMappings(CorsRegistry registry) {
             registry.addMapping("/**").
                     allowedOrigins("https://www.dustyblog.cn"). //允许跨域的域名,可以用*表示允许任何域名使用
                     allowedMethods("*"). //允许任何方法(post、get等)
                     allowedHeaders("*"). //允许任何请求头
                     allowCredentials(true). //带上cookie信息
                     exposedHeaders(HttpHeaders.SET_COOKIE).maxAge(3600L); //maxAge(3600)表明在3600秒内,不需要再发送预检验请求,可以缓存该结果
         }
     };
    
    }
    }
    ● 测试,在允许访问的域名https://www.dustyblog.cn/控制台输入(注意,这里请求的是http://127.0.0.1:8080/demo3):
    var token= "LtSFVqKxvpS1nPARxS2lpUs2Q2IpGstidMrS8zMhNV3rT7RKnhLN6d2FFirkVEzVIeexgEHgI/PtnynGqjZlyGkJa4+zYIXxtDMoK/N+AB6wtsskYXereH3AR8kWErwIRvx+UOFveH3dgmdw1347SYjbL/ilGKX5xkoZCbfb1f0=,LZkg22zbNsUoHAgAUapeBn541X5OHUK7rLVNHsHWDM/BA4DCIP1f/3Bnu4GAElQU6cds/0fg9Li5cSPHe8pyhr1Ii/TNcUYxqHMf9bHyD6ugwOFTfvlmtp6RDopVrpG24RSjJbWy2kUOOjjk5uv6FUTmbrSTVoBEzAXYKZMM2m4=,R4QeD2psvrTr8tkBTjnnfUBw+YR4di+GToGjWYeR7qZk9hldUVLlZUsEEPWjtBpz+UURVmplIn5WM9Ge29ft5aS4oKDdPlIH8kWNIs9Y3r9TgH3MnSUTGrgayaNniY9Ji5wNZiZ9cE2CFzlxoyuZxOcSVfOxUw70ty0ukLVM/78=";
    var xhr = new XMLHttpRequest();
    xhr.open('GET', 'http://127.0.0.1:8080/demo3/sayHello');
    xhr.setRequestHeader("x-access-token",token);
    xhr.send(null);
    xhr.onload = function(e) {
    var xhr = e.target;
    console.log(xhr.responseText);
    }
    输出结果
    ƒ (e) {
    var xhr = e.target;
    console.log(xhr.responseText);
    }
    VM433:8 hello world --- 3
    说明跨域成功,换个网址如https://www.baidu.com测试依旧出现需要跨域的错误提示,证明该配置正确,该方案测试通过。
    2.3 拦截器实现
    通过实现Fiter接口在请求中添加一些Header来解决跨域的问题
    @Component
    public class CorsFilter implements Filter {
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
         throws IOException, ServletException {
     HttpServletResponse res = (HttpServletResponse) response;
     res.addHeader("Access-Control-Allow-Credentials", "true");
     res.addHeader("Access-Control-Allow-Origin", "*");
     res.addHeader("Access-Control-Allow-Methods", "GET, POST, DELETE, PUT");
     res.addHeader("Access-Control-Allow-Headers", "Content-Type,X-CAF-Authorization-Token,sessionToken,X-TOKEN");
     if (((HttpServletRequest) request).getMethod().equals("OPTIONS")) {
         response.getWriter().println("ok");
         return;
     }
     chain.doFilter(request, response);
    
    }
    @Override
    public void destroy() {
    }
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    }
    }
    三、更多
    3.1 源码地址
    Github 示例代码
相关文章
|
存储 缓存 NoSQL
Redis的主要用途是什么?
【4月更文挑战第2天】Redis是多功能工具,常用于缓存加速、轻量级数据库、消息代理(发布/订阅)、分布式锁、计数器、数据结构算法实现、实时系统支撑及限流控制。其丰富的数据类型和高效操作支持多种应用场景,提升系统性能。
775 2
|
Linux 网络安全 数据安全/隐私保护
如何在 CentOS 上安装和配置 Samba?
如何在 CentOS 上安装和配置 Samba?
1949 0
如何在 CentOS 上安装和配置 Samba?
|
3月前
|
Java 测试技术 API
Java Stream API:被低估的性能陷阱与优化技巧
Java Stream API:被低估的性能陷阱与优化技巧
396 114
|
NoSQL 应用服务中间件 Redis
在华为鲲鹏OpenEuler20.03系统上安装Redis, Zookeeper, Nginx
在华为鲲鹏OpenEuler20.03系统上安装Redis, Zookeeper, Nginx
3782 0
在华为鲲鹏OpenEuler20.03系统上安装Redis, Zookeeper, Nginx
|
前端开发 Java 应用服务中间件
Gateway网关使用不规范,同事加班泪两行~
Gateway网关使用不规范,同事加班泪两行~
Gateway网关使用不规范,同事加班泪两行~
|
域名解析 Cloud Native jenkins
【Drone+Gitlab】一条龙服务,直接起飞 — 从介绍->部署->配置->写.drone.yml流水线+常见的报错解决
gitlab+drone部署安装,编写.drone.yml流水线 drone是一个持续集成化工具,gitlab是一个代码仓库,.drone.yml流水线编写 fatal: unable to access,could not resolve host 克隆地址连接不上(修改默认clone克隆),没有Trusted选项,启动drone-server时添加(--env=DRONE_USER_CREATE=username:root,admin:true) .drone.yml文件中sed命令报错
2628 0
【Drone+Gitlab】一条龙服务,直接起飞 — 从介绍->部署->配置->写.drone.yml流水线+常见的报错解决
|
应用服务中间件 nginx
创建Istio
此教程介绍如何使用 Helm 安装 Istio 及其组件。首先修改 `kube-apiserver.yaml` 配置服务账户参数,接着创建 `istio-system` 命名空间并添加 Istio 的 Helm 源。通过 Helm 安装 Istio Base 和 Discovery (istiod) Chart,并部署 Ingress Gateway 到 `istio-ingress` 命名空间。最后,创建一个 Nginx Deployment 和 Service,以及对应的 Istio Gateway 和 VirtualService 来验证安装是否成功.
|
资源调度
npm i时报错npm ERR! code ERESOLVE npm ERR! ERESOLVE could not resolve npm ERR! npm ERR! While resolving
npm i时报错npm ERR! code ERESOLVE npm ERR! ERESOLVE could not resolve npm ERR! npm ERR! While resolving
834 0
第一次导入项目,从gitee拉取的代码无法拉取怎么解决,idea如何导入项目,如何跑拉取的项目,如何使用Maven导入项目,如何回到idea首页,如何导入第一次的项目,拉取的代码出现了橘黄色图标,图片
第一次导入项目,从gitee拉取的代码无法拉取怎么解决,idea如何导入项目,如何跑拉取的项目,如何使用Maven导入项目,如何回到idea首页,如何导入第一次的项目,拉取的代码出现了橘黄色图标,图片
|
Kubernetes 网络协议 关系型数据库
基于operator sdk轻松编写一个k8s自定义资源管理应用
operator 是一种 kubernetes 的扩展形式,可以帮助用户以 Kubernetes 的声明式 API 风格自定义来管理应用及服务,operator已经成为分布式应用在k8s集群部署的事实标准了,在云原生时代系统想迁移到k8s集群上编写operator应用是必不可少的能力,这里介绍用 CoreOS 的 operator framework 工具如何快速构建一个 operator 应用。
8048 0