什么是AJAX跨域问题
现在的开发是前后台完全分离的趋势发展,那么什么是AJAX跨域问题?简单来说,你在前台调用后台服务接口,如果这个接口不是同一个域,就会产生跨域问题。
为什么会发生AJAX跨域问题?
1. 浏览器限制,说白了也就是浏览器多管闲事。
2. 跨域:http://localhost:8080 http://localhost:8081 这是两个不同的域
3. XHR(XMLHttpRequest)请求
解决思路
浏览器限制:指定参数,指定参数让浏览器不去做这个限制(不推荐)
XHR:修改发送的数据类型JSONP(现在少用)
跨域:被调用方修改代码,支持跨域
调用方修改代码,支持跨域
解决方案
1. 命令行参数启动浏览器,增加参数,比如—disable-web-security,禁止浏览器检查
2. JSONP如何解决跨域
JSONP是什么?
使用JSONP服务器后台要改动吗?
后台需要改动->使用jsonp后台解决起来比较简单,首先我们改的是服务器后台代码。我们增加一个controller层的切面,ControllerAdvice但是,在使用的时候AbstractJsonpResponseBodyAdvice 这个类找不到,很苦恼应该是我是用的版本不正确,上面是我记录的源代码,仅供参考。
JSONP有什么弊端?
服务器需要改动代码支持;只支持GET;发送的不是XHR请求。
1. 跨域
最常见的Java2ee架构
跨域解决方向->被调用方解决、调用方解决
被调用方解决:这是一种支持跨域的的解决思路,是基于http协议关于跨域方面的规定,在响应头里增加指定的字段,告诉浏览器允许跨域,修改的是被调用方http服务器。
调用方解决:这是基于隐藏跨域的的解决思路,跨域请求不会直接从调用方发送到被调用方,而是从中间的http服务器转发过去,修改的是调用方服务器。
被调用方解决-支持跨域
两个地方增加响应头:中间HTTP(APACHE/NGINX)服务器、应用服务器
服务器端实现
NGINX配置
APACHE配置
(1)被调用方-Filter解决方案
跨域请求:
本域(非跨域)请求:
对比跨域和非跨域请求发现:跨域请求的请求头里多了一个字段:Origin:http://localhost:8081/
当浏览器发现这个请求是跨域的时候,就会多出这个字段,请求头里增加当前域的信息的字段,然后等请求返回来,浏览器就会检查响应头里有没有允许跨域的信息,如果没有,它就会报错。
(2)Filter代码实现
springboot中filter的用法 :一、在spring的应用中我们存在两种过滤的用法,一种是拦截器、另外一种当然是过滤器。我们这里介绍过滤器在springboot的用法,在springmvc中的用法基本上一样,只是配置上面有点区别。二、filter功能,它使用户可以改变一个 request和修改一个response. Filter 不是一个servlet,它不能产生一个response,它能够在一个request到达servlet之前预处理request,也可以在离开 servlet时处理response.换种说法,filter其实是一个”servlet chaining”(servlet 链).
修改服务端的代码:在springboot中增加一个filter,增加filter的方法是注册一个FilterRegistrationBean。
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
@SpringBootApplication
public class AjaxserverApplication {
public static void main(String[] args) {
SpringApplication.run(AjaxserverApplication.class, args);
System.out.println("项目启动...");
}
@Bean
public FilterRegistrationBean registerFilter() {
FilterRegistrationBean bean = new FilterRegistrationBean();
bean.addUrlPatterns("/*");
bean.setFilter(new CrosFilter());
return bean ;
}
}
在doFilter中增加响应头,
import javax.servlet.*;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class CrosFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletResponse res = (HttpServletResponse) servletResponse;
//指定允许域
res.addHeader("Access-Control-Allow-Origin", "http://localhost:8081");
//指定允许的方法
res.addHeader("Access-Control-Allow-Methods", "GET");
// //允许所有域
// res.addHeader("Access-Control-Allow-Origin", "*");
// //允许所有方法
// res.addHeader("Access-Control-Allow-Methods", "*");
//完整filter链
filterChain.doFilter(servletRequest, servletResponse);
}
@Override
public void destroy() {
}
}
刷新一下,下面是添加Filter后的响应头,跨域问题初步得到了解决。
(2)简单请求和非简单请求
浏览器在发送跨域请求时会先判断请求是否是简单请求,如果是简单请求就会先执行,后判断,如果是非简单请求,它就会先发送OPTIONS预检查命令,检查通过之后,才会将跨域请求发送出去。
(3)带Cookie的跨域
带cookie的跨域,Accss-Control-Allow-Origin:*,不能是“*”,必须写具体的域名。
发送的cookie是被调用方的cookie,而不是调用方的cookie。
(4)被调用方解决跨域-nginx/apache解决方案
虚拟主机:多个域名指向同一个服务器,服务器根据不同的域名,把请求转到不同的应用服务器。
在被调用方配置NGINX/APACHE服务器。
(5)被调用方-SPRING框架解决方案
在controller类上(或者方法上)加注解:
(6)调用方解决-隐藏跨域
隐藏跨域的解决思路:跨域请求经过调用方的http服务器反向代理转发到被调用方的服务器,在浏览器上看不到任何跨域请求。
什么是反向代理:简单来说访问同一个域名的两个不同URL,最后回去到两个不同服务器。
在调用方配置NGINX/APACHE服务器。
4.总结
这是我在学习跨域时做的笔记,通过学习,理解了跨域问题,仅供参考,欢迎留言评论。
这是讲解跨域问题的课程链接地址https://www.imooc.com/learn/947