5.跨域处理

本文涉及的产品
RDS DuckDB + QuickBI 企业套餐,8核32GB + QuickBI 专业版
简介: 本文介绍了跨域问题的产生原因及解决方案。当协议、域名或端口不同时,浏览器因同源策略阻止资源访问。通过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 示例代码
相关文章
|
前端开发 Java 应用服务中间件
解决跨域问题的8种方法,含网关、Nginx和SpringBoot~
解决跨域问题的8种方法,含网关、Nginx和SpringBoot~
4333 0
解决跨域问题的8种方法,含网关、Nginx和SpringBoot~
|
数据采集 存储 缓存
SpringBoot与布隆过滤器的完美邂逅:高效防护大规模数据的奇妙结合【实战】
SpringBoot与布隆过滤器的完美邂逅:高效防护大规模数据的奇妙结合【实战】
737 0
|
19天前
|
人工智能 前端开发 测试技术
DeepSeek 协议中转火了:ds2api 为什么能让一套接口同时兼容 OpenAI、Claude、Gemini?
ds2api 是一款开源AI协议适配中间件,将DeepSeek Web对话能力封装为OpenAI/Claude/Gemini兼容API。基于Go后端+React前端,支持Docker、Vercel等多部署方式,提供账号池调度、Tool Calling转译、流式响应等工程化能力,助力AI应用实现协议统一、模型可替换、客户端免改造。
|
1月前
|
存储 文件存储 Docker
用 Docker 一键部署 Filestash:打造你的全能 Web 文件管理器
还在为不同存储协议装一堆客户端?SFTP、FTP、WebDAV、S3、云盘……每次都要切换工具,传个文件像“打地鼠”?今天给大家安利一个神器——Filestash,一个开源的 Web 文件管理器,把所有存储协议都收进浏览器里,用 Docker 几分钟就能搭好,运维、开发、日常用都超爽!
354 0
用 Docker 一键部署 Filestash:打造你的全能 Web 文件管理器
|
5月前
|
Linux Docker 容器
【赵渝强老师】使用yum方式安装Docker
本文介绍如何使用yum方式在Linux系统中安装和管理Docker。通过yum可自动解决依赖问题并方便地进行软件包更新。首先测试网络连通性,然后执行yum命令安装Docker,启动并启用Docker服务,最后验证安装成功并查看版本信息。
560 5
|
10月前
|
XML 人工智能 Java
Spring Boot集成Aviator实现参数校验
Aviator是一个高性能、轻量级的Java表达式求值引擎,适用于动态表达式计算。其特点包括支持多种运算符、函数调用、正则匹配、自动类型转换及嵌套变量访问,性能优异且依赖小。适用于规则引擎、公式计算和动态脚本控制等场景。本文介绍了如何结合Aviator与AOP实现参数校验,并附有代码示例和仓库链接。
662 0
|
9月前
|
存储 Java
Java LocalDateTime与hutool DateUtil实现秒转换为时分秒格式化展示。
注意:以上代码示例仅适合于处理小于24小时内(86400s) 总积 因 LocalDateTime 和 Local Time 不支持超过24小时表达而 huo tool示例虽然理论上支持但未考虑超过24小时情况下可能出现负值等异常情况处理细节需用户自行添加相关逻辑以确保正确性.
589 7
|
人工智能 自然语言处理 搜索推荐
gemini国内能用吗?请收下这份gemini使用攻略!
在当今技术迅猛发展的时代,人工智能(AI)语言模型已经成为一股变革性的力量,推动着从自然语言处理到对话生成等广泛应用领域的创新。在众多杰出的AI语言模型中,Gemini以其卓越的性能和广泛的用途脱颖而出,备受推崇。作为谷歌旗下的多模态AI巨头,Gemini融合了最先进的语言处理技术,为用户提供了无与伦比的语言理解和生成能力。
|
关系型数据库 MySQL 数据库
Docker Compose V2 安装常用数据库MySQL+Mongo
以上内容涵盖了使用 Docker Compose 安装和管理 MySQL 和 MongoDB 的详细步骤,希望对您有所帮助。
1322 42
|
SQL 数据库 Docker
【赵渝强老师】在Docker中运行达梦数据库
本文介绍了在Docker容器中部署达梦数据库(DM 8)的具体步骤,包括创建文件夹、下载安装包、导入镜像、启动容器、登录数据库及查看状态等操作。同时,通过视频讲解辅助理解。文中还分析了将数据库服务容器化的潜在问题,如数据安全性、硬件资源争用、网络带宽占用和额外隔离带来的挑战,指出数据库服务在生产环境中可能不适合容器化的原因。
1931 4
【赵渝强老师】在Docker中运行达梦数据库