一、什么是跨域调用问题?
跨域调用是指同一浏览器下,一个页面(属于一个域名)的ajax需要调用另一个域名下的接口等以获取资源,而浏览器为了安全问题一般都限制了跨域访问,也就是不允许跨域请求资源。注意:跨域限制访问,其实是浏览器的限制。
而我们的h5的项目通常都与数据接口部署在不同的域名下面(一般是在不同的二级域名下面),所以浏览器也会限制跨域访问,而浏览器对跨域访问不一定是在请求发出的时候,也有可能是在数据response的时候,比如CSRF 跨站攻击原理。如下图:
报错如下:
二、常见的解决方案
目前来讲没有不依靠服务器端来跨域请求资源的技术:
1、jsonp 需要目标服务器配合一个callback函数。
2、window.name+iframe 需要目标服务器响应window.name。
3、window.location.hash+iframe 同样需要目标服务器作处理。
4、html5的 postMessage+ifrme 这个也是需要目标服务器或者说是目标页面写一个postMessage,主要侧重于前端通讯。
5、CORS 需要服务器设置header :Access-Control-Allow-Origin。
6、nginx反向代理 这个方法一般很少有人提及,但是他可以不用目标服务器配合,不过需要你搭建一个中转nginx服务器,用于转发请求。
三、解决跨域调用问题
1、Jsonp方式实现(只支持GET请求)
@RequestMapping(value = "/getXXXjsonp", method = RequestMethod.GET) @ResponseBody public void getXXXJsonp(HttpServletRequest request, HttpServletResponse response, @RequestParam("callback") String callback) { // 业务处理,并得到结果,加入业务处理完需要返回的结果为result String json = JSON.toJSONString(result); String str = callback + "(" + json + ");"; try { response.getWriter().print(str); } catch (IOException e) { e.printStackTrace(); } }
2、CORS方式实现(项目使用该方式实现)
将nginx的配置的http设置如下:
http { include mime.types; server { listen 80; server_name localhost; charset UTF-8; location / { root html; index index.html index.htm; } # Avoid CORS and reverse proxy settings location /h5/ { proxy_http_version 1.1; proxy_pass http://39.107.235.104/; add_header Access-Control-Allow-Origin *; add_header Access-Control-Allow-Methods "POST, GET, OPTIONS"; add_header Access-Control-Allow-Headers "Origin, Authorization, Accept"; add_header Access-Control-Allow-Credentials true; } } } |
说明:满足/h5的url的请求都会将请求的url进行替换了转发:
http://域名/h5/ 替换为: http://39.107.235.104/
只是需要注意: /h5/ 不能写为 /h5
http://39.107.235.104/ 也不能写为 http://39.107.235.104
CORS请求分为简单请求和非简单请求,区别在于是否满足一下条件(简单请求与非简单请求的流程工作流程是不一样的,具体请参见http://www.ruanyifeng.com/blog/2016/04/cors.html):
(1)请求方法是以下三种方法之一:HEAD、GET、POST
(2)HTTP的头信息不超出以下几种字段:
Accept
Accept-Language
Content-Language
Last-Event-ID
Content-Type:只限于三个值application/x-www-form-urlencoded、multipart/form-data、text/plain
所以一般的接口都是非简单请求,因为接口请求方法可能会使用PUT或DELETE请求方式,或者Content-Type字段的类型是application/json。
2、nginx反向代理
我们使用第六种nginx的反向代理方式进行实现,则需要一台多以的nginx对满足请求的请求进行转发,使用nginx的rewrite功能。在nginx.conf中添加一下的location配置:
server { listen 8080; server_name localhost; location / { root html; index index.html index.htm; } location ^~/lflyes/h5/ { rewrite ^/lflyes/h5/(.*)$ /$1 break; proxy_pass http://www.h5.lflyes.com/; } } |
对以上配置进行说明:
1、'^~ /lflyes/h5/ '
就像上面说的一样是一个匹配规则,用于拦截请求,匹配任何以 /lflyes/h5/开头的地址,匹配符合以后,停止往下搜索正则。
2、rewrite ^/lflyes/h5/(.*)$ /$1 break;
代表重写拦截进来的请求,并且只能对域名后边的除去传递的参数外的字符串起作用,例如www.c.com/lflyes/h5/api/msg?method=1¶=2重写。只对/lflyes/h5/api/msg重写。
rewrite后面的参数是一个简单的正则 ^/lflyes/h5/(.*)$ ,$1代表正则中的第一个(),$2代表第二个()的值,以此类推。
break代表匹配一个之后停止匹配。
3、proxy_pass
既是把请求代理到其他主机