跨域问题解决思路

简介: 在项目中经常遇到跨域问题,那么怎样解决跨域问题呢,下面提供几种解决跨域问题的解决思路。

一、跨域是什么?

跨域(CORS)是指不同域名之间相互访问,顾名思义,指的是浏览器不能执行其他网站的脚本,它是由浏览器的同源策略所造成的,是浏览器对于JavaScript所定义的安全限制策略。

1.1 同源策略

     跨域问题其实就是浏览器的同源策略所导致的。

同源策略是一个重要的安全策略,它用于限制一个origin(opens new window)的文档或者它加载的脚本如何能与另一个源的资源进行交互。它能帮助阻隔恶意文档,减少可能被攻击的媒介。

当跨域时会收到以下错误:

1.2 同源实例

例:https://www.xxx.com:80/path/to/myfile.html?key1=value1#Somewhere

只有当protocol(协议)、domain(域名)、port(端口)三者一致,才是同源。

1.3 简单请求和非简单请求

常见的简单请求:

1、请求方法为:HEAD、GET、POST中的一种;

2、HTTP请求头中字段不超过:Accept、Accept-Language、Content-Language、Last-Event-ID;

3、Content-Type字段值为application/x-www-form-urlencoded、multipart/form-data、text/plain中的一种。

非简单请求:

1、请求方法为put、delete;

2、发送JSON格式的ajax请求;

3、http中带自定义请求头。

对于简单请求:

浏览器发现是跨域请求,就会自动在请求头中加上Origin字段,代表请求来自哪个域(协议+主机名+端口号)。服务器在收到请求后,根据请求头中Origin字段值来判断是否允许跨域请求通过。具体实现方法是:在响应头Access-Control-Allow-Origin字段中设置指定的域名,表示允许这些域名的跨域请求。如果请求头中Origin字段的域名包含在这些域名中,则可以实现跨域请求(当然有时候还需要结合其他字段来判断),否则不通过。例如:

请求头信息

GET /cors http 1.1

Origin:http://localhost:8080/

connection:keep-active

响应头信息

Access-Control-Allow-Origin://localhost:8080/

Access-Control-Allow-Credentials:true

Content-Type:text/html;chatset=utf-8

非简单请求:

非简单请求在发送http请求时,会预先发送一次“预检”(OPTIONS)请求。预检请求会事先询问服务器,当前域名是否在服务器允许的范围内,以及可以使用哪些HTTP动词和头信息字段。只有得到肯定答复后,浏览器才会真正发出http请求,否则就会报错。

解决跨域可以在客户端访问服务端时拦截以下请求头设置:

Access-Control-Allow-Origin

标识允许哪个域的请求

Access-Control-Allow-Methods

请求方法

Access-Control-Max-Age

本次预检请求的有效期,单位为秒

Access-Control-Allow-Headers

响应首部

Access-Control-Allow-Credentials

允许客户端携带验证信息

2. 如何解决跨域

2.1 JSONP

JSONP(JSON with Padding)是JSON的一种“使用模式”,可用于解决主流浏览器的跨域数据访问的问题。Jsonp实现的前提:浏览器允许跨越加载同源数据。即在JavaScript脚本中发送请求,就可以远程加载js格式数据。JSONP只支持GET请求。

请求原理:

(1)异步请求的时候,加上一个名为callback的回调函数(该函数前后端要保持一致);

(2)在接口中,将返回的json格式数据,伪装(包装)成js脚本格式;

(3)得到js格式数据后,提取里面的json数据。

Jquery在发送一个Ajax jsonp请求时,会在访问链接的后面自动加上一个验证参数,这个参数是Jquery随机生成的,例如链接:https://www.xxx.com/path/to/myfile?callback=jQuery311098773333_23224424444222,jsonp对接的后端接口:

@ResponseBody
@RequestMapping("/getMyJsonp")
public String getMyJsonpSuccess(@RequestParam("callback") String callback){
  Gson gson=new Gson();
  Map map = new HashMap<>();
  map.put("seat","测试jsonp接口");
  return callback+"("+gson.toJson(map)+")";
}

2.2 拦截请求头

2.2.1使用Filter方式进行设置

使用Filter过滤器来过滤服务请求,向请求端设置Response Header(响应头部)的Access-Control-Allow-Origin属性声明允许跨域访问。

@WebFilter
public class CorsFilter implements Filter {
    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
        HttpServletResponse response = (HttpServletResponse) res;
        response.setHeader("Access-Control-Allow-Origin", "*");
        response.setHeader("Access-Control-Allow-Methods", "*");
        response.setHeader("Access-Control-Max-Age", "3600");
        response.setHeader("Access-Control-Allow-Headers", "*");
        response.setHeader("Access-Control-Allow-Credentials", "true");
        chain.doFilter(req, res);
    }
}

2.2.2继承 HandlerInterceptorAdapter(拦截器方式)

@Component
public class CrossInterceptor extends HandlerInterceptorAdapter {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        response.setHeader("Access-Control-Allow-Origin", "*");
        response.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
        response.setHeader("Access-Control-Max-Age", "3600");
        response.setHeader("Access-Control-Allow-Headers", "*");
        response.setHeader("Access-Control-Allow-Credentials", "true");
        return true;
    }
}

2.2.3实现WebMvcConfigurer

@Configuration
@SuppressWarnings("SpringJavaAutowiredFieldsWarningInspection")
public class AppConfig implements WebMvcConfigurer {
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")  // 拦截所有的请求
                .allowedOrigins("http://www.xxx.com")  // 可跨域的域名,可以为 *
                .allowCredentials(true)
                .allowedMethods("*")   // 允许跨域的方法,可以单独配置
                .allowedHeaders("*");  // 允许跨域的请求头,可以单独配置
    }
}

2.3 使用 @CrossOrgin 注解

@CrossOrigin
@RestController
@RequestMapping("/user")
public class UserController {
    @GetMapping("/{id}")
    public User get(@PathVariable Long id) {
    }
    @DeleteMapping("/{id}")
    public void remove(@PathVariable Long id) {
    }
}

@CrossOrgin源码如下:

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface CrossOrigin {
    /** @deprecated */
    @Deprecated
    String[] DEFAULT_ORIGINS = new String[]{"*"};
    /** @deprecated */
    @Deprecated
    String[] DEFAULT_ALLOWED_HEADERS = new String[]{"*"};
    /** @deprecated */
    @Deprecated
    boolean DEFAULT_ALLOW_CREDENTIALS = true;
    /** @deprecated */
    @Deprecated
    long DEFAULT_MAX_AGE = 1800L;
    @AliasFor("origins")
    String[] value() default {};
    @AliasFor("value")
    String[] origins() default {};
    String[] allowedHeaders() default {};
    String[] exposedHeaders() default {};
    RequestMethod[] methods() default {};
    String allowCredentials() default "";
    long maxAge() default -1L;
}

其本质也是通过拦截请求头进行处理。

2.4 使用Nginx配置

location / {
   add_header Access-Control-Allow-Origin *;
   add_header Access-Control-Allow-Headers X-Requested-With;
   add_header Access-Control-Allow-Methods GET,POST,PUT,DELETE,OPTIONS;
   if ($request_method = 'OPTIONS') {
     return 204;
   }
}
相关文章
|
前端开发 Java 应用服务中间件
解决跨域问题的8种方法,含网关、Nginx和SpringBoot~
解决跨域问题的8种方法,含网关、Nginx和SpringBoot~
4481 0
解决跨域问题的8种方法,含网关、Nginx和SpringBoot~
在钉钉开放平台中,事件订阅功能允许你的应用订阅钉钉的各种事件
在钉钉开放平台中,事件订阅功能允许你的应用订阅钉钉的各种事件【1月更文挑战第9天】【1月更文挑战第44篇】
662 2
|
SQL 数据采集 关系型数据库
大数据采集和抽取怎么做?这篇文章终于说明白了!
数据是数据中台\数据平台核心中的核心,因此数据汇聚必然是数据中台/平台的入口,本文详细讲述采集模块的方方面面、采集框架的使用选型以及企业真实落地
大数据采集和抽取怎么做?这篇文章终于说明白了!
|
2月前
|
缓存 前端开发 开发工具
阿里云国际站代理商:OSS跨域请求被拦截?CORS规则详解与前端上传排查方法
前端工程师把文件直传阿里云OSS时,控制台冷不丁甩出一条红色报错:“No 'Access-Control-Allow-Origin' header is present”,页面卡住十几秒后依然传不上去。这大概率不是代码逻辑出错,而是跨域资源共享(CORS)的配置与请求模式没对上。理顺阿里云OSS跨域CORS配置及前端上传问题排查的完整思路,远比反复改前端请求参数更有效。
405 0
|
10月前
|
人工智能 运维 自然语言处理
世优波塔推出轻量级网页SDK方案,15分钟实现大屏AI数字人集成
展厅升级AI数字人,无需漫长改造与高昂成本!世优科技推出波塔AI数字人网页SDK,15分钟极速集成,轻量化部署,支持自定义形象与多场景交互。适配各类大屏,打通数据系统与数字孪生,让智慧展厅迈入“分钟级”时代,每个空间都能拥有专属数字灵魂。
458 1
|
9月前
|
前端开发 安全 Java
集成Knife4j
knife4j是Java MVC框架集成Swagger的增强工具,前身swagger-bootstrap-ui,旨在提供更美观、易用的API文档界面。轻量如匕首,功能强大,支持全局参数设置、离线文档下载、友好测试界面。集成简便,通过引入starter依赖并访问/doc.html即可使用,助力前后端高效协作,提升接口调试与维护体验。
|
缓存 并行计算 安全
关于Java多线程详解
本文深入讲解Java多线程编程,涵盖基础概念、线程创建与管理、同步机制、并发工具类、线程池、线程安全集合、实战案例及常见问题解决方案,助你掌握高性能并发编程技巧,应对多线程开发中的挑战。
|
消息中间件 存储 大数据
阿里云消息队列 Kafka 架构及典型应用场景
阿里云消息队列 Kafka 是一款基于 Apache Kafka 的分布式消息中间件,支持消息发布与订阅模型,满足微服务解耦、大数据处理及实时流数据分析需求。其通过存算分离架构优化成本与性能,提供基础版、标准版和专业版三种 Serverless 版本,分别适用于不同业务场景,最高 SLA 达 99.99%。阿里云 Kafka 还具备弹性扩容、多可用区部署、冷热数据缓存隔离等特性,并支持与 Flink、MaxCompute 等生态工具无缝集成,广泛应用于用户行为分析、数据入库等场景,显著提升数据处理效率与实时性。
|
缓存 JSON 安全
Http自定义Header导致的跨域问题
在Web开发中,正确处理跨域问题是确保应用安全和性能的重要环节。通过在服务器端设置适当的CORS头信息,处理预检请求,并遵循最佳实践,可以有效解决自定义Header导致的跨域问题,提高应用的安全性和用户体验。理解并掌握这些技巧,对于构建高效、可靠的Web应用至关重要。
1267 11