跨域访问CORS探究

什么是跨域?

跨域,简单地讲,就是一个Web应用(http://www.a.com)下的文档或脚本访问另一个Web应用(http://www.b.com)下的资源。任何两个应用所在域,只要存在协议、域名或端口任意一个不相同,即被认为访问是跨域的。

为什么会出现跨域访问限制?

由于浏览器同源策略,我们这里主要讨论XmlHttpRequest同源策略,XmlHttpRequest同源策略禁止XHR对象向不同源的服务器地址发送请求,这是浏览器出于安全考虑所做的限制。

使用ajax向另一个域下的应用发送一个请求,在服务端未做跨域相关的处理之前将报如下错误:

Failed to load http://localhost:8081/api: No ‘Access-Control-Allow-Origin‘ header is present on the requested resource. Origin ‘http://localhost:3200‘ is therefore not allowed access. If an opaque response serves your needs, set the request‘s mode to ‘no-cors‘ to fetch the resource with CORS disabled.

什么是CORS?

CORS,全称Cross-Origin Resource Sharing,即跨域(源)资源共享。CORS使用目标服务器上返回的HTTP头信息来标识允许来自特定的域的跨域访问。跨域请求诸如<img>标签加载来自不同域的图片、引用CDN的脚本样式等是允许的。然而为了安全考虑,浏览器显示了从脚本里发起的跨域HTTP请求,由于XMLHttpRequest和Fetch API遵从同源策略,在没有服务器端返回允许跨域的CORS头部信息时,这种类型的请求将被限制。

CORS机制保障了浏览器和服务器之间跨域请求和数据传输的安全性,使得XMLHttpRequest和Fetch API进行跨域访问有了可能。

两种类型的跨域请求

简单请求 (Simple requests)

简单请求是指当前跨域请求不触发“跨域中的的预检验”(即后面说到的预检请求),简单请求需要满足下面所有条件:

  • 请求方法是GET、POST或HEAD三者之一
  • 请求头部信息中仅允许出现以下列表的请求头
    • Accept
    • Accept-Language
    • Content-Language
    • Content-Type,并且该值为application/x-www-form-urlencoded、multipart/form-data、text/plain三者之一
    • Last-Event-ID
    • DPR
    • Save-Data
    • Viewport-Width
    • Width
  • XMLHttpRequestUpload对象在请求中没有注册事件监听
  • 在请求中没有使用ReadableStream对象

简单请求的请求头和响应头示例:

预检请求 (Preflight requests)

预检请求会在真正的请求之前发送一次预检的OPTIONS请求,先校验最终的请求是否可以安全发送。满足以下任一条件即是一个预检请求:

  • 请求方法是PUT、DELETE、CONNECT、OPTIONS、TRACE、PATCH之一
  • 请求头信息包含除了Accept、Accept-Language、Content-Language、Last-Event-ID、DPR、Save-Data、Viewport-Width、Width之外的任何头信息
  • 请求头信息包含Content-Type,其值不为application/x-www-form-urlencoded、multipart/form-data、text/plain三者任何一个
  • 在XMLHttpRequestUpload对象中使用事件监听
  • 请求中使用了ReadableStream对象

预检请求示例,实际发生了两次请求,一次options检验请求,一次是实际获取数据的请求:

CORS中使用到的关键响应头信息

  • Access-Control-Allow-Origin

    该头部项的值可配置为通配符:*,表示允许来自任何域的跨域访问

    也可指定具体的域,比如:http://domain.a.com

    注:跨域请求中的请求头部信息中的Origin为请求所在域,与该响应头部值匹配即可完成跨域访问

  • Access-Control-Allow-Methods

    该头部项指定了跨域请求中允许使用的请求方法,也可配置成通配符*,多个值用逗号分隔,如:

    Access-Control-Allow-Methods: GET, POST, OPTIONS, HEAD, PUT
  • Access-Control-Allow-Headers

    该头部项指定了跨域请求中允许使用的头部信息,由于请求中经常使用到的Content-Type不为application/x-www-form-urlencoded、multipart/form-data、text/plain时,请求将转为预检请求,通常地,需要将Content-Type、其他一些常用的头部和自定义的头部信息在此处指定,以便跨域访问正常完成

  • Access-Control-Allow-Credentials

    当前端网页请求指定了withCredentials为true时,后端返回响应头中需要指定Access-Control-Allow-Credentials值为true,如果仅仅是前端网页在请求时指定withCredentialstrue,那后端返回的结果将被浏览器忽略,从而请求无法完成。跨域请求默认不发送cookie,前端网页请求时,将withCredentials值设为true,表示允许发送cookie信息,当然也需要服务器明确许可。

    Access-Control-Allow-Credentials: true

CORS解决跨域访问限制的实现

如果想让我们的后端应用允许某些特定域的跨域请求,一般地,我们需要在拦截请求处对请求进行校验并对允许的跨域请求响应设置适当的响应头部信息。

典型地,项目中使用了Servlet统一拦截了请求,这个时候需要实现我们对应允许的请求方法,如doGet、doPost处理普通的GET/POST请求,doOptions处理预检请求。

public class AppServlet extends HttpServlet{

@Override    public void init() throws ServletException{        super.init();    }

@Override    public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{        doPost(request, response);    }

@Override    public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{        String origin = request.getHeader("Origin");        List<String> allowOrigins = CORSUtil.getAllowOrigins();        if(StringUtils.isNotBlank(origin) && allowOrigins.contains(origin)){            // 校验当前域是允许跨域访问的域            response.setHeader("Access-Control-Allow-Origin", origin);            response.setHeader("Access-Control-Allow-Credentials", "true");            response.setHeader("Access-Control-Allow-Methods", "*");            response.setHeader("Access-Control-Allow-Headers", "Origin, No-Cache, X-Requested-With, If-Modified-Since, Pragma, Last-Modified, Cache-Control, Expires, Content-Type, X-E4M-With");        }?        // compose your response here

}

/**     * 处理跨域中的OPTIONS预检请求,OPTIONS请求同样需要指定允许访问的域     */    @Override    protected void doOptions(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {        super.doOptions(req, resp);        String origin = req.getHeader("Origin");        if(StringUtils.isNotBlank(origin)){            resp.setStatus(HttpStatus.SC_NO_CONTENT);            //允许预检请求跨域,此处让所有OPTIONS请求都能跨域,实际检验在post中进行            resp.setHeader("Access-Control-Allow-Origin", origin);            resp.setHeader("Access-Control-Allow-Credentials", "true");            resp.setHeader("Access-Control-Allow-Methods", "*");            resp.setHeader("Access-Control-Allow-Headers", "Origin, No-Cache, X-Requested-With, If-Modified-Since, Pragma, Last-Modified, Cache-Control, Expires, Content-Type, X-E4M-With");        }    }?}

或者使用过滤器Filter一站式处理所有类型的请求:

public class CorsFilter implements Filter{

@Override    public void init(FilterConfig filterConfig) throws ServletException{

}

@Override    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException{        String origin = request.getHeader("Origin");        List<String> allowOrigins = CORSUtil.getAllowOrigins();        if("OPTIONS".equalsIgnoreCase(request.getMethod) ||            (StringUtils.isNotBlank(origin) && allowOrigins.contains(origin)){            // 当为options请求 或 当前域是允许跨域访问的域 都设置必要的 完成跨域访问的响应头部信息            response.setHeader("Access-Control-Allow-Origin", origin);            response.setHeader("Access-Control-Allow-Credentials", "true");            response.setHeader("Access-Control-Allow-Methods", "*");            response.setHeader("Access-Control-Allow-Headers", "Origin, No-Cache, X-Requested-With, If-Modified-Since, Pragma, Last-Modified, Cache-Control, Expires, Content-Type, X-E4M-With");        }    }

@Override    public void destroy(){

}

}

web.xml配置:

<filter>    <filter-name>corsFilter</filter-name>    <filter-class>com.test.filter.CorsFilter</filter-class></filter><filter-mapping>    <filter-name>corsFilter</filter-name>    <url-pattern>/*</url-pattern></filter-mapping>

参考链接:

http://developer.mozilla.org/en-US/docs/Web/HTTP/CORS

http://www.ruanyifeng.com/blog/2016/04/cors.html

原文地址:https://www.cnblogs.com/hexidong/p/9090067.html

时间: 2024-08-24 05:46:50

跨域访问CORS探究的相关文章

JavaScript跨域访问CORS问题

在尝试从一个web前端使用HTTP Request请求访问REST服务端时,遇到错误: XMLHttpRequest cannot load http://localhost:8080/ping. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:63342' is therefore not allowed access. 这个错误是因为A

跨域访问CORS

由于现代浏览器的同源策略,合理的跨域请求也变得至关重要. CORS(Cross-Origin Resource Sharing,跨域资源共享)定义了在必须访问跨域资源时,浏览器与服务器应该如何沟通.它背后的思想是使用自定义的HTTP头部让浏览器与服务器进行沟通,从而决定请求或相应是应该成功还是应该失败. 一些跨域技术: 1.JSONP JSONP(JSON with padding 填充式JSON或参数式JSON),是应用JSON的一种新方法,是被包含在函数调用中的JSON. JSONP由两部分

SpringCloud 跨域访问cors

import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.cors.CorsConfiguration; import org.springframework.web.cors.UrlBasedCorsConfigurationSource; import org.sp

SPRING BOOT跨域访问处理

尊重原创:http://blog.csdn.net/ruiguang21/article/details/77878933 问题场景:由于项目中使用到跨域访问,今天也得到高人指点,所以写出来分享给大家可能是考虑到前后端分离,前端后端服务器不在一台机器上,出现这种跨域访问的情况.正常情况下本地访问是没有问题,但是遇到这种非同一台服务器的情况下,就会报错Access-Control-Allow-Origin.具体报错内容不记得了. 问题解决方案一:采用添加拦截器的方式对请求添加跨域访问的头,允许跨域

Web Api 2(Cors)Ajax跨域访问

支持Ajax跨域访问ASP.NET Web Api 2(Cors)的简单示例教程演示 随着深入使用ASP.NET Web Api,我们可能会在项目中考虑将前端的业务分得更细.比如前端项目使用Angularjs的框架来做UI,而数据则由另一个Web Api 的网站项目来支撑.注意,这里是两个Web网站项目了,前端项目主要负责界面的呈现和一些前端的相应业务逻辑处理,而Web Api则负责提供数据. 这样问题就来了,如果前端通过ajax访问Web Api项目话,就涉及到跨域了.我们知道,如果直接访问,

jquery ajax CORS 跨域访问 WebService

JS代码: var word = document.getElementById("word").value; $.ajax({ type: "POST", contentType: "application/x-www-form-urlencoded", url: "http://localhost:12805/WebService.asmx/HelloWorld", data: 'data=' + word, dataTy

System.Web.Http.Cors配置跨域访问的两种方式

System.Web.Http.Cors配置跨域访问的两种方式 使用System.Web.Http.Cors配置跨域访问,众多大神已经发布了很多文章,我就不在详细描述了,作为小白我只说一下自己的使用心得.在webapi中使用System.Web.Http.Cors配置跨域信息可以有两种方式.  一种是在App_Start.WebApiConfig.cs的Register中配置如下代码,这种方式将在所有的webapi Controller里面起作用. using System; using Sys

使用微软CORS包不能跨域访问的问题

使用jquery的ajax异步调用的时候会出现不能跨域访问的问题,这个问题一般有两种方法. 1:使用jsonp跨域 2:使用html5的CORS 在这里只谈论第二种,微软对CORS提供的了支持,在NuGet安装Microsoft.AspNet.WebApi.Cors就可以使用跨域的功能. 但是事实并不是这样,在有的时候使用了这个DLL然后添加跨域的方法依然没有效果. 那我们可以使用其他的方法解决这类问题. 最简单的就是修改Web.config文件 在system.webServer节点下复制如下

JAX-RS开发(四):ajax跨域访问REST服务时的cors解决方案

上一篇博客我们通过JSONP解决AJAX跨域问题,本文将通过CORS来解决跨域问题.CORS是HTML5新推出的,需要较高版本的浏览器才能支持.我用的IE11和Chrome41,都是支持CORS规范的.cors可以参考下面几篇文章: cors规范 http://www.w3.org/TR/cors/ cors浏览器兼容性 http://caniuse.com/#search=cors tomcat7的cors解决方案 http://tomcat.apache.org/tomcat-7.0-doc