跨域及跨域问题的解决方案

跨域

什么是跨域?

跨域,即非同源策略请求。指的是浏览器不能执行其他网站的脚本。它是由浏览器的同源策略造成的,是浏览器施加的安全限制。

所谓同源是指,域名,协议,端口均相同,不明白没关系,举个栗子:

  • http://www.123.com/index.html 调用 http://www.123.com/server.php (非跨域)
  • http://www.123.com/index.html 调用 http://www.456.com/server.php (主域名不同:123/456,跨域)
  • http://abc.123.com/index.html 调用 http://def.123.com/server.php (子域名不同:abc/def,跨域)
  • http://www.123.com:8080/index.html 调用 http://www.123.com:8081/server.php (端口不同:8080/8081,跨域)
  • http://www.123.com/index.html 调用 https://www.123.com/server.php (协议不同:http/https,跨域)

请注意:localhost和127.0.0.1虽然都指向本机,但也属于跨域。

浏览器执行javascript脚本时,会检查这个脚本属于哪个页面,如果不是同源页面,就不会被执行。

  1. 跨域只存在于浏览器端,不存在于安卓/ios/Node.js/python/ java等其它环境
  2. 跨域请求能发出去,服务端能收到请求并正常返回结果,只是结果被浏览器拦截了。
  3. 浏览器出于安全的考虑,使用 XMLHttpRequest对象发起 HTTP请求时必须遵守同源策略,否则就是跨域的HTTP请求,默认情况下是被禁止的。换句话说,浏览器安全的基石是同源策略。
什么是CORS?

CORS是一个W3C标准,全称是”跨域资源共享”(Cross-origin resource sharing),允许浏览器向跨源服务器,发出XMLHttpRequest请求,从而克服了AJAX只能同源使用的限制。它通过服务器增加一个特殊的Header[Access-Control-Allow-Origin]来告诉客户端跨域的限制,如果浏览器支持CORS、并且判断Origin通过的话,就会允许XMLHttpRequest发起跨域请求。

CORS Header

Access-Control-Allow-Origin: http://www.xxx.com
Access-Control-Max-Age:86400
Access-Control-Allow-Methods:GET, POST, OPTIONS, PUT, DELETE
Access-Control-Allow-Headers: content-type
Access-Control-Allow-Credentials: true
含义解释:
1、Access-Control-Allow-Origin 允许http://www.xxx.com域(自行设置,这里只做示例)发起跨域请求
2、Access-Control-Max-Age 设置在86400秒不需要再发送预校验请求
3、Access-Control-Allow-Methods 设置允许跨域请求的方法
4、Access-Control-Allow-Headers 允许跨域请求包含content-type
5、Access-Control-Allow-Credentials 设置允许Cookie

跨域会阻止什么操作?

浏览器是从两个方面去做这个同源策略的,一是针对接口的请求,二是针对Dom的查询

  1. 阻止接口请求比较好理解,比如用ajax从http://192.168.100.150:8020/实验/jsonp.html页面向http://192.168.100.150:8081/zhxZone/webmana/dict/jsonp发起请求,由于两个url端口不同,所以属于跨域,在console打印台会报No ‘Access-Control-Allow-Origin’ header is present on the requested resource

    • 值得说的是虽然浏览器禁止用户对请求返回数据的显示和操作,但浏览器确实是去请求了,如果服务器没有做限制的话会返回数据的,在调试模式的network中可以看到返回状态为200,且可看到返回数据
  2. 阻止dom获取和操作

    比如a页面中嵌入了iframe,src为不同源的b页面,则在a中无法操作b中的dom,也没有办法改变b中dom中的css样式。

浏览器的这个限制虽然不能保证完全安全,但是会增加攻击的困难性

虽然安全机制挺好,可以抵御坏人入侵,但有时我们自己需要跨域请求接口数据或者操作自己的dom,也被浏览器阻止了,所以就需要跨域

跨域的前提肯定是你和服务器是一伙的,你可以控制服务器返回的数据,否则跨域是无法完成的

怎么解决跨域问题?

1、前端方法使用jsonp

JSONP需要服务器端支持JSONP请求

原理就是html中 的link,href,src属性都是不受跨域影响的,link可以调用远程的css文件,href可以链接到随便的url上,图片的src可以随意引用图片,script的src属性可以随意引入不同源的js文件

  • script
  • img
  • link
  • iframe

这些标签不存在跨域请求限制

跨域及跨域问题的解决方案

eg:

$.ajax({
  url: 'http://1.119.169.72:10001/lidarData/lidarData/selectViewData?time=2020-07-05&lidarType=dep&wavelength=355',
  method: 'get',
  dataType: 'jsonp', //=>执行的是JSONP请求
  success: res => {
    console.log(res);
  }
});

serverJsonp.js

let express = require('express'),
  app = express();
app.listen(10001, _ => {
  console.log('ok');
});

app.get('/selectViewData', (req, res) => {
  let {
    callback = Function.prototype
  } = req.query();
  let data = {
    code: 0,
    message: 'ddd'
  };
  res.send('${callback}(${JSON.stringify(data)})');
});

问题:JSONP只能处理get请求

2、后台配置解决跨域

后台通过配置解决跨域问题

首先在pom.xml中引入依赖

<!--跨域依赖-->
<dependency>
    <groupId>com.thetransactioncompany</groupId>
    <artifactId>cors-filter</artifactId>
    <version>1.7.1</version>
</dependency>
<dependency>
    <groupId>com.thetransactioncompany</groupId>
    <artifactId>java-property-utils</artifactId>
    <version>1.9</version>
</dependency>
<dependency>

然后在web.xml配置过滤器

<!--为了允许跨域访问-->
<filter>
    <filter-name>CorsFilter</filter-name>
    <filter-class>com.thetransactioncompany.cors.CORSFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>CorsFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

这样前端就可以尽情跨域请求数据了,是不是很方便?

注意如果项目中配置了检测是否登录过滤器,可能会起冲突,因为没有登录的话每次都会跳转到登录接口。。。

SpringBoot注入重写方法的WebMvcConfigurer解决跨域问题

CORSConfig.java

/**
 * @Description 跨域配置
 * @Author chenlinghong
 * @Date 2019/1/27 13:31
 **/
@Configuration
public class CORSConfig {

    @Bean
    public WebMvcConfigurer corsConfigurer(){
        return new WebMvcConfigurer() {
            @Override
            public void addCorsMappings(CorsRegistry registry) {
                registry.addMapping("/**")
                        .allowedHeaders("*")
                        .allowedMethods("*")
                        .allowedOrigins("*");
            }
        };
    }
}

3、基于iframe的跨域解决方案(window.name/document.domain/location.hash)

4、通过HTML5中新引进的window.postMessage方法来跨域传送数据

5、通过CORS解决跨域

CORS也需要服务器端的支持

CORS背后的基本思想是使用自定义的HTTP头部允许浏览器和服务器相互了解对方,从而决定请求或响应成功与否.

首先自己写一个过滤器CORSFilter

/**
 * Created by 12143 on 2018/12/7.
 */
@Component
public class CORSFilter extends OncePerRequestFilter {
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        response.addHeader("Access-Control-Allow-Origin", "http://192.168.100.150:8020");
        //response.addHeader("Access-Control-Allow-Origin", "*");
        response.addHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE");
        response.addHeader("Access-Control-Allow-Headers", "Content-Type");
        response.addHeader("Access-Control-Max-Age", "1800");//30 min
        filterChain.doFilter(request, response);
    }
}

注意:Access-Control-Allow-Origin为*则允许所有url访问,如果为“http://192.168.100.150:8020”则只有此url才能访问,注意有端口的要把端口也写上
比如配置了http://192.168.56.130:8081,那么只有http://192.168.56.130:8081 能拿到数据,否则全部报403异常
然后在web.xml中添加此过滤器

<filter>
    <filter-name>CorsFilter</filter-name>
    <filter-class>com.xxx.common.filter.CORSFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>CorsFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

6、通过Nginx反向代理

上一篇:云服务器(轻量级服务器)部署ActiveMQ


下一篇:14.6.3.3 Configuring Multiple Buffer Pool Instance