• nginx 跨越问题


    跨域问题

    版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/caozhangyingfei0109/article/details/53439377

    一、原由

    最近写接口跟web端的对接。联调过程中出现跨域的问题,着实费了一番功夫,也涉及了以前不知道的东西,以此学习和总结吧。

    二、各种解决方案

    1.报错信息:

    XMLHttpRequestcannot load http://zb.example.com/info.json?ak=E485214565fetch087acde70&level=19&tilex=431625&tiley=198699. The 'Access-Control-Allow-Origin' header contains multiple values'*, *', but only one is allowed. Origin 'http://localhost:63342' is therefore notallowed access.

    2.原因分析

    浏览器默认不允许跨域访问,包括我们平时ajax也是限制跨域访问的。

    产生跨域访问的情况主要是因为请求的发起者与请求的接受者

          1、域名不同;

           2、端口号不同

    3.解决方案

    1.JSONP方法

    jsonP只能使用GET传递参数,只支持GET方式。即使使用jquery的jsonp方法,type设为POST,也会自动变为GET。我用的是POST,果断pass。

    2.iframe

    跨域使用POST方式,可以使用创建一个隐藏的iframe来实现,与ajax上传图片原理一样,但这样会比较麻烦。只是看的网上这么说,也不知道具体该如何弄,但是,我找到了另一个更简单的方法了。所以pass。

    3.通过设置Access-Control-Allow-Origin来实现跨域访问

    如果服务端是 JAVA开发的,添加如下设置允许跨域即可。

    response.setHeader("Access-Control-Allow-Origin","*");

    添加上这个就表明当前页面可以跨域访问。默认是不允许的。

    具体添加的位置有:

    (1)可以在过滤器 filter 中的dofilter() 方法设置。

    (2)可以在 servlet 的 get 或者post 方法里面设置。

    (3)可以放在访问的 jsp页面第一行(response.setHeader("Access-Control-Allow-Origin","*"))。

    3.1 举例,我的框架用的是springboot,如果是filter的配置的话,应该这么做:

    @Component
    public classSimpleCORSFilter implements Filter {

    @Override
    publicvoid destroy() {
    //TODO Auto-generated method stub
    }
    @Override
    publicvoid doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
    throwsIOException, ServletException {
    HttpServletRequestrequest = (HttpServletRequest) req;
    HttpServletResponseresponse = (HttpServletResponse) res;
    response.setHeader("Access-Control-Allow-Origin",request.getHeader("origin"));
    //response.setHeader("Access-Control-Allow-Origin","*");
    response.setHeader("Access-Control-Allow-Methods", "POST,GET, OPTIONS, DELETE");
    response.setHeader("Access-Control-Max-Age","3600");
    response.setHeader("Access-Control-Allow-Headers","x-requested-with,Cache-Control,Pragma,Content-Type,Token");
    response.setHeader("Access-Control-Allow-Credentials","true");
    chain.doFilter(req,res);
    }
    @Override
    publicvoid init(FilterConfig arg0) throws ServletException {
    //TODO Auto-generated method stub
    }
    }

    @Configuration 
    public classWebConfig { 
    @Bean 
    public FilterRegistrationBeanfilterRegistrationBean(MyFilter myFilter){ 
    FilterRegistrationBeanfilterRegistrationBean = new FilterRegistrationBean(); 
    filterRegistrationBean.setFilter(myFilter); 
    filterRegistrationBean.setEnabled(true); 
    filterRegistrationBean.addUrlPatterns("/*"); 
    return filterRegistrationBean; 

    }      

    如果你的spring版本用的是4以上的,就更简单啦:

    @Configuration
    public classCorsConfig {
    private CorsConfiguration buildConfig() {
    CorsConfiguration corsConfiguration =new CorsConfiguration();
    corsConfiguration.addAllowedOrigin("*"); // 1
    corsConfiguration.addAllowedHeader("*"); // 2
    corsConfiguration.addAllowedMethod("*"); // 3
    return corsConfiguration;
    }

    @Bean
    public CorsFilter corsFilter() {
    UrlBasedCorsConfigurationSource source= new UrlBasedCorsConfigurationSource();
    source.registerCorsConfiguration("/**", buildConfig()); // 4
    return new CorsFilter(source);
    }
    }

    3.2 原理

    其实我真的特别好奇,既然浏览器限制跨域访问,但是web开发又特别需要这个功能,为什么一个简单的配置就能够完成呢?不知其然不知其所以然。所以,简单的学习一下原理-CORS协议。

    以下均是从各地摘录汇总一起,变成了自己的理解,哈哈,与君共勉:

    如今的JS大有一统天下的趋势,浏览器已经成了大多应用最好的安身之所。在寻找跨域解决方案时,发现了最优雅解决方案就是HTML5来带了的“Cross-OriginResource Sharing”的新特性,来赋予开发者权力决定资源是否允许被跨域访问。

    CORS是一个W3C标准,全称是”跨域资源共享”(Cross-originresource sharing)。

    它允许浏览器向跨源服务器,发出XMLHttpRequest请求,从而克服了AJAX只能同源使用的限制。

    整个CORS通信过程,都是浏览器自动完成,不需要用户参与。对于开发者来说,CORS通信与同源的AJAX通信没有差别,代码完全一样。浏览器一旦发现AJAX请求跨源,就会自动添加一些附加的头信息,有时还会多出一次附加的请求,但用户不会有感觉。

    因此,实现CORS通信的关键是服务器。只要服务器实现了CORS接口 ,就可以跨源通信。

    在服务器响应客户端的时候,带上Access-Control-Allow-Origin头信息(这个header就是让服务器支持CORS的)。

    CORS具有以下常见的header

    <span style="font-size:14px;">Access-Control-Allow-Origin:http://kbiao.me 
    Access-Control-Max-Age:3628800
    Access-Control-Allow-Methods:GET,PUT, DELETE
    Access-Control-Allow-Headers:content-type</span>
    <span style="font-size:14px;">
    “Access-Control-Allow-Origin”表明它允许”http://kbiao.me“发起跨域请求
    “Access-Control-Max-Age”表明在3628800秒内,不需要再发送预检验 请求,可以缓存该结果(上面的资料上我们知道CROS协议中,一个AJAX请求被分成了第一步的 OPTION 预检测请求和正式请求)
    “Access-Control-Allow-Methods”表明它允许GET、PUT、DELETE的外域请求
    “Access-Control-Allow-Headers”表明它允许跨域请求包含content-type头</span>

    刚才的介绍不能算是原理了,只能说是原由了。具体感兴趣的可以查看这篇博客《利用Access-Control-Allow-Origin响应头解决跨域请求》,对于COR协议解释的还不错。

    三、原来问题不在这边!!!

    说到这里了,其实跨域问题已经解决了。但是在实际的项目中,我们会用到很多东西,也许,阻碍我们的并不是我们认为的。就比如我这次的问题吧,看问题说明“Origin'http://localhost:63342' is therefore not allowedaccess.“一开始就被绕到里面了,到最后实在没办法,全方面排查问题,才发现,原来是我在项目中用nginx做反向代理,这个没问题,问题是我做了两层代理,并且配置文件中都设置了header(解决方案就是,删除其中一个配置文件的header设置)。

    在请求数据的时候,header头是这样的:

    就可以看出来我设置了两次,并且两次都返回来了。

    正常的应该是这样的:

    而且我们再仔细看问题的描述:

    XMLHttpRequestcannot load http://zb.example.com/info.json?ak=E485214565fetch087acde70&level=19&tilex=431625&tiley=198699. The 'Access-Control-Allow-Origin' header contains multiple values '*, *',but only one is allowed. Origin 'http://localhost:63342' is therefore not allowed access.

    我真是。。。

    历练吧。

    本文转载:https://blog.csdn.net/caozhangyingfei0109/article/details/53439377

  • 相关阅读:
    Pytest中参数化之CSV文件实战
    Pytest中参数化之Yaml文件实战
    Pytest中参数化之JSON文件实战
    Pytest中参数化详解
    Pytest搜索规则/命令详解/跳过测试和预期失败测试
    Http协议介绍
    MySQL视图/触发器/事务/存储过程/函数/流程控制/索引
    pymysql模块使用和简单sql注入及解决方法
    MySQL连接软件Navicat学习
    对文件操作的讲解
  • 原文地址:https://www.cnblogs.com/hushaojie/p/12132372.html
Copyright © 2020-2023  润新知