跨域问题解决思路

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

一、跨域是什么?

跨域(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;
   }
}
相关文章
|
7月前
|
人工智能 运维 自然语言处理
世优波塔推出轻量级网页SDK方案,15分钟实现大屏AI数字人集成
展厅升级AI数字人,无需漫长改造与高昂成本!世优科技推出波塔AI数字人网页SDK,15分钟极速集成,轻量化部署,支持自定义形象与多场景交互。适配各类大屏,打通数据系统与数字孪生,让智慧展厅迈入“分钟级”时代,每个空间都能拥有专属数字灵魂。
330 1
|
关系型数据库 MySQL PostgreSQL
MySQL和PostgreSQL的常用语法差异
背景 在去年的DBMS评比中,PostgreSQL夺冠,PostgreSQL一直保持上升姿态,越来越多的客户选择使用PostgreSQL,还有一部分客户从MySQL迁往PostgreSQL,那PostgreSQL和MySQL对于开发者来说的差异在哪里呢?末学对比了下语法差异,不一样的地方用红色标记了出来,供大家参考。
14732 0
|
6月前
|
前端开发 安全 Java
集成Knife4j
knife4j是Java MVC框架集成Swagger的增强工具,前身swagger-bootstrap-ui,旨在提供更美观、易用的API文档界面。轻量如匕首,功能强大,支持全局参数设置、离线文档下载、友好测试界面。集成简便,通过引入starter依赖并访问/doc.html即可使用,助力前后端高效协作,提升接口调试与维护体验。
|
消息中间件 存储 大数据
阿里云消息队列 Kafka 架构及典型应用场景
阿里云消息队列 Kafka 是一款基于 Apache Kafka 的分布式消息中间件,支持消息发布与订阅模型,满足微服务解耦、大数据处理及实时流数据分析需求。其通过存算分离架构优化成本与性能,提供基础版、标准版和专业版三种 Serverless 版本,分别适用于不同业务场景,最高 SLA 达 99.99%。阿里云 Kafka 还具备弹性扩容、多可用区部署、冷热数据缓存隔离等特性,并支持与 Flink、MaxCompute 等生态工具无缝集成,广泛应用于用户行为分析、数据入库等场景,显著提升数据处理效率与实时性。
|
10月前
|
缓存 并行计算 安全
关于Java多线程详解
本文深入讲解Java多线程编程,涵盖基础概念、线程创建与管理、同步机制、并发工具类、线程池、线程安全集合、实战案例及常见问题解决方案,助你掌握高性能并发编程技巧,应对多线程开发中的挑战。
|
缓存 JSON 安全
Http自定义Header导致的跨域问题
在Web开发中,正确处理跨域问题是确保应用安全和性能的重要环节。通过在服务器端设置适当的CORS头信息,处理预检请求,并遵循最佳实践,可以有效解决自定义Header导致的跨域问题,提高应用的安全性和用户体验。理解并掌握这些技巧,对于构建高效、可靠的Web应用至关重要。
1155 11
|
Linux 编译器 Go
Golang 语言怎么安装多个 Golang 版本的环境?
Golang 语言怎么安装多个 Golang 版本的环境?
583 0
|
安全 JavaScript 前端开发
跨域问题如何解决
跨域问题是指浏览器同源策略限制了不同域名之间的资源访问。解决方法包括:1. CORS(跨域资源共享):服务器设置Access-Control-Allow-Origin响应头;2. JSONP:利用script标签不受同源策略限制的特点;3. 代理服务器:通过后端代理转发请求。
|
机器学习/深度学习 自然语言处理
交叉熵损失
【10月更文挑战第2天】