跨域你需要知道这些

综合技术 2018-12-08 阅读原文

  • DOM 层面的同源策略:限制了来自不同源的”Document”对象或 JS 脚本,对当前“document”对象的读取或设置某些属性
  • Cookie和XMLHttprequest层面的同源策略:禁止 Ajax 直接发起跨域HTTP请求( 其实可以发送请求,只是结果被浏览器拦截,不展示
    ),同时 Ajax 请求不能携带与本网站不同源的 Cookie。
  • 同源策略的非绝对性: <script><img><iframe><link><video><audio>
    等带有src属性的标签可以从不同的域加载和执行资源。
  • 其他插件的同源策略: flash、java applet、silverlight、googlegears
    等浏览器加载的第三方插件也有各自的同源策略,只是这些同源策略不属于浏览器原生的同源策略,如果有漏洞则可能被黑客利用,从而留下XSS攻击的后患

二、为什么会跨域?

浏览器之所以要对跨域请求作出限制,是出于安全方面的考虑,防止被不法分子利用利用跨域请求来发动 CSRF攻击 。

三、跨域解决方案

1、JSONP

在jQuery中最常用的就是Ajax 的JSONP了,利用 <script><img><iframe>
等标签不受同源策略限制,可以从不同域加载并执行资源的特性,来实现数据跨域传输。JSONP由回调函数和数据两部分组成,使用与服务端约定好回调函数名称,服务端接收到请求后返回一段JavaScript代码,这段代码调用约定好的回调函数,并将数据作为参数进行传递,页面接收到这段代码后就会立即执行这个回调函数,解析传递来的数据

2、NGINX代理

代理是用于将请求发送给后台服务器,通过服务器来发送请求,然后将请求的结果传递给前端

注意点:如果代理的是https协议的请求,那么你的proxy首先需要信任该证书(尤其是自定义证书)或者忽略证书检查,否则请求无法成功。

3、CORS

CORS即跨源资源共享 Cross-Origin Resource Sharing(CORS),
是一个新的W3C标准,允许服务端声明那些网站有权限访问哪些资源,即允许浏览器向声明了CORS的跨域服务器,发出XMLHttpReuest请求,从而解决同源策略的限制,本文则着重讲解CORS办法

当非简单请求浏览器发生跨域时,我们会看到浏览器有一个OPTION 类型的请求,这叫 预检请求
,在规范中规定,对于非简单的请求,浏览器必须首先使用 OPTION 方法发起一个预检请求(preflight request),从而获知服务端是否允许该跨域请求,在服务器确定允许后,才发起实际的HTTP请求。对于简单请求、非简单请求以及预检请求的详细资料可以阅读, HTTP访问控制

那么怎么避免触发预检请求呢

上文说了,非简单请求才会触发预检请求,所以只要保证请求是简单请求即可, 注意这里的简单请求不单单指请求方式
,详情请看
简单请求

,简单请求的请求方式包含GET、POST、HEAD,但是在实际中POST请求也会预检请求,那是因为只有当请求的Content-Type值是  text/plain,
multipart/form-data,
application/x-www-form-urlencoded三者之一时才被认为是简单请求

下面以Vue + axios项目实例做跨域讲解

在Vue中当axios配置 axios.defaults.baseURL ='******'后,本地代理就不再生效,那么想要解决跨域的问题首先需要后端服务允许跨域,然后前端保证发出的是简单请求

后端服务配置:

protected void writeStr(HttpServletResponse resp,HttpServletRequest request, String str) {
        resp.setHeader("Access-Control-Allow-Origin", "*");
        resp.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
        resp.setHeader("Access-Control-Max-Age", "3600");
        Enumeration<String> headersEnum = ((HttpServletRequest) request).getHeaders("Access-Control-Request-Headers");
        StringBuilder headers = new StringBuilder();
        String delim = "";
      //取消OPTIONS预检请求
        while (headersEnum.hasMoreElements()) {
            headers.append(delim).append(headersEnum.nextElement());
            delim = ", ";
        }
        resp.setHeader("Access-Control-Allow-Headers", headers.toString());
        resp.setContentType("text/html; charset=UTF-8");
        try {
            resp.getWriter().write(str);
            LoggerUtils.getLogger().info("===================");
            LoggerUtils.getLogger().info("return msg:{}", str);
        } catch(IOException e) {
            LoggerUtils.getLogger().error(e.getMessage(),e);
        }
    }

Access-Control-Allow-Origin

响应首部中可以携带这个头部表示服务器允许哪些域或者所有域可以访问该资源,语法:
Access-Control-Allow-Origin: <origin> | *  ,origin 参数的值指定了允许访问该资源的外域 URI。对于不需要携带身份凭证的请求,服务器可以指定该字段的值为通配符,表示允许来自所有域的请求。

Access-Control-Allow-Methods

该首部字段用于预检请求的响应,指明实际请求所允许使用的HTTP方法。语法: Access-Control-Allow-Methods: <method>[, <method>]*

Access-Control-Max-Age

该首部字段用于预检请求的响应,指定了预检请求能够被缓存多久,语法:
Access-Control-Max-Age: <delta-seconds>



前端配置:

保证前端请求即可。未完待续......

博客园精华区

责编内容by:博客园精华区阅读原文】。感谢您的支持!

您可能感兴趣的

Javascript is our field-marshall I remember when I first read about the CSS Animation and Transition modules. I was worried. It seemed to me that the ...
React Native iOS混合开发实战教程 在做RN开发的时候通常离不了JS 和Native之间的通信,比如:初始化RN时Native向JS传递数据,JS调用Native的相册选择图片,JS调用Native的模块进行一些复杂的计算,Native将一些数据(GPS信息,陀螺仪,传感器等...
What’s Wrong With My Code? We Try to Help You I see questions like this on StackOverflow and related websites like, ALL THE TIME: I have some code, what’s wrong wit...
How do you modify img src with javascript dependin... I would like to change the source of the image element with the id of "front". I have a basic script at the top, but it ...
Deal with & ldquo; Kill & quot&am... So James Patterson keeps trying to hack my website! Okay, not really, but he has written quite a few books that have ti...