跨域
序:这篇随笔是看了“晓风轻老师的ajax跨域完全讲解”的视频之后的笔记。
一、产生跨域的条件
(一)浏览器同源策略的限制
(二)请求跨域(协议、域名、端口不同)
(三)请求的类型是XMLHttpRequest
同时符合上面三条,才会发生跨域问题。
二、解决思路
(一)改浏览器设置,使浏览器支持
在Chrome浏览器安装目录执行 chrome --disable-web-security --user-data-dir=g:\temp3
我测试失败了,有兴趣的同学可以试试,教程链接
(二)JSONP(请求类型从xhr变成script)
1.前端JSONP
$.ajax({ url: '', dataType: 'jsonp', success: function(json) { result = json; } });
这是使用的是jQuery,虽然jQuery把JSONP看做是ajax,其实真的不是一回事,具体可参考《说说JSON和JSONP...》
2.后台同步支持
import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.servlet.mvc.method.annotation.AbstractJsonpResponseBodyAdvice; @ControllerAdvice public class JsonpAdvice extends AbstractJsonpResponseBodyAdvice { public JsonpAdvice() { super("callback"); } }
因为教程是基于springboot,所以这是springboot上的一种方法,但是这种方式在spingboot2.0上已经无法使用了!!!
虽然方法已经过时了,但总体的思路是不变的,就是在后端返回数据时,不直接返回JSON,而是返回的javascript代码。
下面是我按照JSONP协议实现的代码
<script type="text/javascript"> var afterJsonp = function(data){ alert('经过jsonp的data是:' + data.data); }; var url = "http://127.0.0.1:8080/test/testJsonp?data=something&callback=afterJsonp"; var script = document.createElement('script'); script.setAttribute('src', url); document.getElementsByTagName('head')[0].appendChild(script); </script>
@GetMapping("/testJsonp") public String testJsonp(String data,String callback) { //简单的处理下传参 data += " after jsonp"; String ret = callback + "({\"data\":\""+data+"\"})"; return ret; }
JSONP的弊端:服务器需要改代码(加拦截器、加注解或者别的什么方式)、只支持GET、不是XHR
(三)支持跨域(被调用方支持跨域/调用方隐藏跨域)
1.被调用方解决-支持跨域
(1)服务器实现-通过filter解决
@SpringBootApplication public class AjaxserverApplication { public static void main(String[] args) { SpringApplication.run(AjaxserverApplication.class, args); } @SuppressWarnings({ "rawtypes", "unchecked" }) @Bean public FilterRegistrationBean registerFilter() { FilterRegistrationBean bean = new FilterRegistrationBean(); bean.addUrlPatterns("/*"); bean.setFilter(new CrosFilter()); return bean; } }
public class CrosFilter implements Filter { @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletResponse res = (HttpServletResponse) response; res.addHeader("Access-Control-Allow-Origin", "*"); res.addHeader("Access-Control-Allow-Methods", "*"); chain.doFilter(request, response); } }
(2)Nginx 这里直接放视频教程
(3)Apache 这里直接放教程视频
(4)如果是spring框架,只需要在类或方法上加注解“@CrossOrigin”
2.调用方解决-隐藏跨域(通过方向代理实现)
(1)Nginx 这里直接放视频教程
(2)Apache 这里直接放视频教程
三、额外知识点
(一)简单请求和非简单请求
同时满足下面两点就是简单请求 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
这里推荐下阮一峰老师的《跨域资源共享 CORS 详解》,对应的是上面的“服务器实现-通过filter解决”这种方式。
说点题外话,距离上篇随笔,已经过去了快两年,这两年的学习和工作就像随笔一样,停滞不前,有时候都有想放弃“写bug”的冲动。唉,不够努力,只会被时代抛弃...