跨域访问

缘由:同源策略javascript

1.JSONP

Ajax直接请求普通文件存在跨域无权限访问的问题 ,数据没法请求,可是 script 请求js确能够正常访问。html

jsonp就是模仿一个 script请求 来获取数据的方式,全部基本支持的是 GET 请求前端

$.ajax({
   async: false,
   type: 'get',
   jsonp: "callback",//设置这个会替换浏览器发送请求时地址后面自动添加的?callback=xxx中的callback这个字,通常状况下不用传这个参数
   jsonpCallback: "callJsonP",//这个值将用来取代jQuery自动生成的随机函数名,也就是上句话中的'xxx'。
   data:自定义
   url: 'http://lnn.wuage.com:8080/pc/toJson',
   dataType: 'jsonp',
   success: function (data) {
      alert(JSON.stringify(data));
   }
});
@RequestMapping("/toJson")
@ResponseBody
public String  toJson(HttpServletRequest request,@RequestParam(value="callback")String callback)
{
   return callback + "(" + new JSONObject() + ")";
   //或者 fastJSON
   JSONObject obj=new JSONObject();
   obj.put("data","你好呀");
   JSONPObject result=new JSONPObject("callJsonP");
   result.addParameter(obj);
   String resultStr=result.toString();
   return resultStr;
}

 

2.设置 CORS协议

适用场景:承载的信息量大,get形式搞不定,需选用post传输。CORS支持全部类型的传输。java

兼容性:移动端全面支持(除opera mini),PC上IE8+。jquery

经常使用头web

Access-Control-Allow-Origin: http://foo.org

Access-Control-Max-Age: 3628800

Access-Control-Allow-Methods: GET,PUT, DELETE

Access-Control-Allow-Headers: content-type

"Access-Control-Allow-Origin"代表它容许"http://foo.org"发起跨域请求

"Access-Control-Max-Age"代表在3628800秒内,不须要再发送预检验请求,能够缓存该结果

"Access-Control-Allow-Methods"代表它容许GET、PUT、DELETE的外域请求

"Access-Control-Allow-Headers"代表它容许跨域请求包含content-type头

1.简单请求

     只使用 GET, HEAD 或者 POST 请求方法:若是使用 POST 向服务器端传送数据,则数据类型(Content-Type)只能是 application/x-www-form-urlencoded, multipart/form-data 或 text/plain中的一种ajax

    不会使用自定义请求头(相似于 X-Modified 这种):HTTP头部信息不超出如下{Accept,Accept-Language,Content-Language,Last-Event-ID,content-type(只限于上面提到的3种类型)}spring

 失败状况json

     

       若是这个源不在许可范围内,会报错: No 'Access-Control-Allow-Origin' header is present on the requested resource.api

      对于简单请求,浏览器直接发出CORS请求。浏览器会自动在头信息(Request Headers)中,添加一个Origin 字段,来代表本次请求来自哪一个域。

      若是Origin指定的域名在许可范围内(必须是跨域了的),Response Headers中会多出几个头信息字段。

Access-Control-Allow-Credentials:true//值为true表示容许发送cookie
Access-Control-Allow-Methods:GET, POST, OPTIONS
Access-Control-Allow-Origin:http://localhost:8080
Access-Control-Max-Age:1728000

例如

withCredentials属性

由于CORS默认不发送cookie和http认证,若是要把Cookie发到服务器,就要指定Access-Control-Allow-Credentials:true;

@CrossOrigin(origins="*",allowCredentials="true")
或者
response.setHeader("Access-Control-Allow-Credentials","true");

另外AJAX中也要打开withCredentials属性。

var xhr=new XMLHttpRequest();
xhr.withCredentials=true;

jquery ajax请求参数中加入

xhrFields: {
  withCredentials: true
}

2.非简单请求

除了上面说的简单请求外都是非简单请求,好比:请求方法是PUT
或DELETE,或者Content-Type字段的类型是application/json,又或者有自定义请求头Access-Control-Request-Headers: X-Custom-Header。

好比,我添加自定义请求头

xhr.setRequestHeader('Some-Custom-Response-Header', 'value');

就会发现连续向同一地址请求了两次

第一次 options 请求

第二次请求:真实请求

这是由于浏览器发现,这是一个非简单请求,就自动发出一个"预检"请求,要求服务器确承认以这样请求。"预检"请求用的请求方法是OPTIONS,表示这个请求是用来询问的。"预检"请求以后,浏览器球会进行正常CORS请求。

3.服务器代码

方法1、 HttpServletRequest :

         在方法体内使用 HttpServletRequest 进行跨越参数设置。若是有参数,必须参数符合要求才进行  

          跨越参数设置。不然报错  400 bad requset,无返回信息

@RequestMapping("/toJson",method = RequestMethod.POST,produces="application/json; charset=utf-8")
@ResponseBody
public String  toJson(HttpServletRequest request)
{
   //设置哪些域名能够访问---若是方法有参数直接报 400 bad request 错误
   response.setHeader("Access-Control-Allow-Origin", "*");
   //解决乱码,缘由 springmvc 设置 produces="application/json; charset=utf-8" 未生效
   response.setContentType( "application/json; charset=utf-8" );
   return new JSONObject();
}

方法2、 @CorssOrigin:

       使用 @CorssOrigin 在进方法体之间就对跨域参数作出设置。发生错误有返回信息。

      Controller中的action的请求方法是实际方法就能够,options方法默认支持

@CrossOrigin(origins="*")/**方法一:跨越参数有返回,有参时报错参数缺失*/
@RequestMapping(value="/toJson",method = {RequestMethod.GET},produces="application/json;charset=utf-8")
@ResponseBody
public String  toJson(HttpServletRequest request,HttpServletResponse response){
     return new JSONObject("ni你好点的");
}

方法三、基于XML的配置

<mvc:cors>
    <mvc:mapping path="/api/**"
        allowed-origins="*"
        allowed-methods="GET,POST,PUT,OPTIONS"
        allow-credentials="false"
        max-age="3600" />
</mvc:cors>

方法4、基于java代码的全局配置 (SpringMVC 4)

       支持SpringMvc 4以上  ,测试未生效

  • 在requestMapping中使用注解。
  • 全局实现 .定义类继承WebMvcConfigurerAdapter
  • 将该类注入到容器中:
@Configuration
public class WebConfig extends WebMvcConfigurerAdapter {

    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/api/**")
            .allowedOrigins("http://domain2.com")
            .allowedMethods("PUT", "DELETE")
            .allowedHeaders("header1", "header2", "header3")
            .exposedHeaders("header1", "header2")
            .allowCredentials(false).maxAge(3600);
    }
}

注入:

<bean class="com.tmall.wireless.angel.web.config.CorsConfigurerAdapter"></bean>

方法5、拦截器配置

1.使用 Spring 提供的 拦截器

<mvc:interceptors>  
   <mvc:interceptor> 
     <!--过滤的路径--> 
     <mvc:mapping path="/h5/*" />  
     <bean class="com.wuage.ossserver.web.Interceptor.CorsInterceptor">  
       <!--过滤路径中的不须要过滤的路径-->
       <property name="excludedUrls">  
          <list>  
            <value>/h5/testOrigin</value>  
          </list>  
       </property>  
     </bean>  
   </mvc:interceptor>
<mvc:interceptors>
package com.wuage.ossserver.web.Interceptor;

import java.util.List;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

/**  
 * 请求拦截器,处理跨域问题  
 * @author 李宁宁  
 *  
 */  
public class CorsInterceptor implements HandlerInterceptor {  
  
    private List<String> excludedUrls;  
  
    public List<String> getExcludedUrls() {  
        return excludedUrls;  
    }  
  
    public void setExcludedUrls(List<String> excludedUrls) {  
        this.excludedUrls = excludedUrls;  
    }  
  
    /**  
     *   
     * 在业务处理器处理请求以前被调用 若是返回false   
     * 从当前的拦截器往回执行全部拦截器的afterCompletion(),  
     * 再退出拦截器链, 若是返回true 执行下一个拦截器,  
     * 直到全部的拦截器都执行完毕 再执行被拦截的Controller  
     * 而后进入拦截器链,  
     * 从最后一个拦截器往回执行全部的postHandle()  
     * 接着再从最后一个拦截器往回执行全部的afterCompletion()  
     *   
     * @param  request  
     *   
     * @param  response  
     */  
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response,  
            Object handler) throws Exception {  
        //* 能够替换成 特定的 网址(协议 域名 端口)
        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",  
                "Origin, X-Requested-With, Content-Type, Accept");  
        response.setHeader("Access-Control-Allow-Credentials",  
                "true");
        return true;  
    }  
  
    // 在业务处理器处理请求执行完成后,生成视图以前执行的动做  
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,  
            ModelAndView modelAndView) throws Exception {  
  
    }  
  
    /**  
     *   
     * 该方法也是须要当前对应的Interceptor的preHandle方法的返回值为true时才会执行。
     * 该方法将在整个请求完成以后,也就是DispatcherServlet渲染了视图执行, 这个方法的主要做用是用于清理资源的, 
     *   
     * @param request  
     *   
     * @param response  
     *   
     * @param handler  
     *   
     */  
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response,  
            Object handler, Exception ex) throws Exception {  
  
    } 
}

2. Filter 拦截器

<filter>
   <filter-name>cros</filter-name> 
   <filter-class>com.wuage.ossserver.web.Interceptor.CORSFilter</filter-class>
</filter>
<filter-mapping>
   <filter-name>cros</filter-name>
   <url-pattern>/h5/*</url-pattern>
</filter-mapping>
public class CORSFilter implements Filter  {

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException,ServletException {
        HttpServletResponse localHttpServletResponse = (HttpServletResponse)response;
        localHttpServletResponse.addHeader("Access-Control-Allow-Origin", "*");
        localHttpServletResponse.addHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE,OPTIONS");
        localHttpServletResponse.addHeader("Access-Control-Allow-Headers", "Content-Type");
        localHttpServletResponse.addHeader("Access-Control-Max-Age", "1800");
        filterChain.doFilter(request, response);  
    }

    @Override
    public void destroy() {}

    @Override
    public void init(FilterConfig arg0) throws ServletException {}

}

注意: 使用 方法 1,2 控制器中只须要进行 特定的方法设置,无需就添加 例如 options类型的设计

        options 非简单CORS请求中 嗅探 方法类型

4.前端

<input type="file" id="file_upload"/>
<input type="button" value="上传图片" id="upload"/>
function ajaxFileUpload(){
        var formData = new FormData();
        formData.append('file',$("#file_upload")[0].files[0]);    //将文件转成二进制形式
        $.ajax({
            type:"post",
            url:"http://localhost:8080/nitshareserver/serve/fileupload",
            async:false,
            contentType: false,    //这个必定要写
            processData: false, //这个也必定要写,否则会报错
            data:formData,
            dataType:'text',    //返回类型,有json,text,HTML。这里并无jsonp格式,因此别妄想能用jsonp作跨域了。
            xhrFields: {withCredentials: true}, //设置是否带验证 cookie
            success:function(data){
                alert(data);
            },
            error:function(XMLHttpRequest, textStatus, errorThrown, data){
                alert(errorThrown);
            }            
        });
    }

5.补充

Springmvc模式是挂壁OPTIONS请求的,因此须要开启

<servlet>    
   <servlet-name>application</servlet-name>    
   <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>  
   <init-param>  
        <param-name>dispatchOptionsRequest</param-name>  
        <param-value>true</param-value>  
   </init-param>    
   <load-on-startup>1</load-on-startup>    
</servlet>

 

6.常见错误:

              403 forbidden 无权限访问-有时 forbox 好使,chrom 很差使

              400 bad request  请求失败, 参数不符合要求

              301 服务器错误 或者 重定向

              405 Method Not Allowed :方法错误(复杂请求要求有 options 方法)

7.参考:

         https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Access_control_CORS

          https://my.oschina.net/wangnian/blog/689020

          http://www.tuicool.com/articles/Vf2aym

          http://blog.csdn.net/u012562943/article/details/53141991

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

          http://www.jianshu.com/p/7257e7c60ef5

相关文章
相关标签/搜索