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

posted @ 2020-01-02 13:06  杰克马001  阅读(263)  评论(0编辑  收藏  举报