跨域问题解决思路

本文涉及的产品
.cn 域名,1个 12个月
简介: 在项目中经常遇到跨域问题,那么怎样解决跨域问题呢,下面提供几种解决跨域问题的解决思路。

一、跨域是什么?

跨域(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;
   }
}
相关文章
|
6月前
|
前端开发 API
uniapp中为什么会出现跨域问题,如何解决
uniapp中为什么会出现跨域问题,如何解决
2222 0
|
7天前
|
安全 JavaScript 前端开发
跨域问题如何解决
跨域问题是指浏览器同源策略限制了不同域名之间的资源访问。解决方法包括:1. CORS(跨域资源共享):服务器设置Access-Control-Allow-Origin响应头;2. JSONP:利用script标签不受同源策略限制的特点;3. 代理服务器:通过后端代理转发请求。
|
前端开发 安全 应用服务中间件
前端经典面试题 | 浏览器跨域
前端经典面试题 | 浏览器跨域
|
6月前
|
JSON 前端开发 JavaScript
详细剖析让前端头疼的跨域问题是怎么产生的,又该如何解决
详细剖析让前端头疼的跨域问题是怎么产生的,又该如何解决
|
缓存 安全 前端开发
【从原理到实战】彻底搞懂跨域问题 (一)(2)
3、预检请求的优化 复杂请求会发预检请求, 相当于每个接口会发两次请求, 比较消耗资源, 那么是可以对预检请求进行优化, 可以采用以下两种方式 设置预检请求的缓存时长
99 0
|
6月前
|
前端开发 JavaScript 应用服务中间件
前端程序员必须要知道的跨域问题以及解决方法
前端程序员必须要知道的跨域问题以及解决方法
Hertz踩坑记录,Hertz-CORS跨域问题
字节跳动开源框架Hertz,可能存在的CORS的跨域问题
|
JavaScript 前端开发 中间件
前端解决跨域问题(9个方法)
前端解决跨域问题(9个方法)
1670 0
|
XML JSON 安全
【从原理到实战】彻底搞懂跨域问题 (一)(1)
前言 什么是跨域: 浏览器为了安全性,设置同源策略导致的, 或者说是一种浏览器的限制 同源策略: 是一种约定,WEB 应用只能请求同一个源的资源 什么时候会跨域: 协议名、域名、端口号 不同 本文将从原理, 到最简代码实现, 演示解决跨域的方法和流程,纸上得来终觉浅 绝知此事要躬行, 只有自己手敲实现过, 才能对其原理理解更加深刻。
430 0
|
前端开发 JavaScript
前端静态页面基本开发思路(二)
由于第一篇的反响不错,所以今天抽空写写前端静态页面基本开发思路(二) 第一篇开发思路直通车→前端静态页面基本开发思路(一) 现在的静态页面的设计基本上都涉及到了轮播图,而且一般都是顶部菜单栏过了就是轮播图的区域,比如小米官网,京东官网等,所以今天我们就从轮播图的实现开始讲
130 2
前端静态页面基本开发思路(二)