博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
跨域访问
阅读量:6298 次
发布时间:2019-06-22

本文共 9132 字,大约阅读时间需要 30 分钟。

hot3.png

原因:同源策略

1.JSONP

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

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")@ResponseBodypublic 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支持所有类型的传输。

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

常用头

Access-Control-Allow-Origin: http://foo.orgAccess-Control-Max-Age: 3628800Access-Control-Allow-Methods: GET,PUT, DELETEAccess-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中的一种

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

 失败情况

      105236_Kkp0_943316.png

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

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

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

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

例如

140302_Camp_943316.png

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');

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

143944_4NiF_943316.png

第一次 options 请求

144054_akBo_943316.png

第二次请求:真实请求

144141_6e3x_943316.png

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

3.服务器代码

方法一、 HttpServletRequest :

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

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

@RequestMapping("/toJson",method = RequestMethod.POST,produces="application/json; charset=utf-8")@ResponseBodypublic 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();}

方法二、 @CorssOrigin:

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

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

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

方法三、基于XML的配置

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

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

  • 在requestMapping中使用注解。
  • 全局实现 .定义类继承WebMvcConfigurerAdapter
  • 将该类注入到容器中:
@Configurationpublic 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);    }}

注入:

方法五、拦截器配置

1.使用 Spring 提供的 拦截器

/h5/testOrigin
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
excludedUrls; public List
getExcludedUrls() { return excludedUrls; } public void setExcludedUrls(List
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 拦截器

cros
com.wuage.ossserver.web.Interceptor.CORSFilter
cros
/h5/*
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.前端

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请求的,所以需要开启

application
org.springframework.web.servlet.DispatcherServlet
dispatchOptionsRequest
true
1

 

6.常见错误:

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

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

              301 服务器错误 或者 重定向

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

7.参考:

        

         

          cookies:

转载于:https://my.oschina.net/u/943316/blog/860936

你可能感兴趣的文章
再学 GDI+[43]: 文本输出 - 获取已安装的字体列表
查看>>
nginx反向代理
查看>>
操作系统真实的虚拟内存是什么样的(一)
查看>>
hadoop、hbase、zookeeper集群搭建
查看>>
python中一切皆对象------类的基础(五)
查看>>
modprobe
查看>>
android中用ExpandableListView实现三级扩展列表
查看>>
%Error opening tftp://255.255.255.255/cisconet.cfg
查看>>
java读取excel、txt 文件内容,传到、显示到另一个页面的文本框里面。
查看>>
《从零开始学Swift》学习笔记(Day 51)——扩展构造函数
查看>>
python多线程队列安全
查看>>
[汇编语言学习笔记][第四章第一个程序的编写]
查看>>
android 打开各种文件(setDataAndType)转:
查看>>
补交:最最原始的第一次作业(当时没有选上课,所以不知道)
查看>>
Vue实例初始化的选项配置对象详解
查看>>
PLM产品技术的发展趋势 来源:e-works 作者:清软英泰 党伟升 罗先海 耿坤瑛
查看>>
vue part3.3 小案例ajax (axios) 及页面异步显示
查看>>
浅谈MVC3自定义分页
查看>>
mybatis学习
查看>>
LCD的接口类型详解
查看>>