最常见的J2EE架构:

Apache/Nginx:HTTP服务器软件(静态服务器)
用户发出请求后,Apache/Nginx判断是静态请求还是动态请求(简言之,与用户数据有关的请求就是动态请求,反之静态请求。css/img都是静态请求),Apache/Nginx如果判断是静态请求,就直接处理请求,返回给客户端。如果是动态请求,就把请求转发到后台应用服务器tomcat,tomcat处理完请求,转到静态服务器,再到客户端。
Apache/Nginx两个作用:1.处理静态请求;2.负载均衡
跨域问题思路

第一种处理思路:直接从浏览器发出请求,请求被调用方。在被调用方上需要做相应的修改,这个修改基于http协议关于跨域请求的规定(就是在返回头中增加一些字段,告诉浏览器我这方允许调用)。
第二种处理思路:隐藏跨域。调用方从Apache/Nginx转出的。通过http服务器的转发,浏览器会认为请求是同一个域。
跨域解决方向
- 被调方解决(思路一)
支持跨域的解决思路,是基于http协议关于跨域方面的规定。在响应头里增加指定字段,告诉浏览器我允许它调用。
- 调用方解决(思路二)
基于隐藏跨域的思路,不会从浏览器直接请求被调用方,是从http服务器转发出去的。
假如调用方xxx.com,被调用方是yyy.com,第一种解决方法,在浏览器你会看到yyy.com,而第二种方法,浏览器看到都是xxx.com.
这两种方向,虽然都是修改的http服务器,但是他们的出发点,修改内容,修改目标都不一样的。第一种方法:修改的是被调用方的http服务器;第二种方法:修改的是调用方的http服务器。
被调用方解决(思路一)

该方法是在响应头增加字段。它可以增加在http服务器或者tomcat。所以
- 服务器端实现(重点)
- Nginx配置
- Apache配置
1.被调用方解决---filter解决方案(服务器端实现)
首先先明白几个问题
问题1:浏览器先执行还是先判断?
在后台可以打印出信息,并且请求状态为200,则说明浏览器先执行后判断。
问题2:浏览器如何判断的?
跨域请求header里有一个Orgin字段,是当前请求的域名信息。浏览器发现当前请求是跨域请求时,就会在请求头增加一个当前域名的字段,等请求返回后,检查有没有允许跨域的信息,如果没有,就会报错。

filter解决方案:
(ssm项目)服务器端:
在web.xml中加入
<filter>
<filter-name>contextfilter</filter-name>
<filter-class>com.wj.filter.WebContextFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>contextfilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
public class WebContextFilter implements Filter {
@Override
public void destroy() {
// TODO Auto-generated method stub
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletResponse httpServletResponse = (HttpServletResponse) response;
httpServletResponse.setHeader("Access-Control-Allow-Origin", "*");
httpServletResponse.setHeader("Access-Control-Allow-Headers", "accept,content-type");
httpServletResponse.setHeader("Access-Control-Allow-Methods", "OPTIONS,GET,POST,DELETE,PUT");
chain.doFilter(request, httpServletResponse);
}
@Override
public void init(FilterConfig arg0) throws ServletException {
// TODO Auto-generated method stub
}
}
(springboot项目)
package com.wj.ajaxserver.filter;
import org.springframework.boot.web.servlet.ServletComponentScan;
import org.springframework.stereotype.Component;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* @创建人 wj
* @创建时间 2018/11/23
* @描述
*/
@Component
@ServletComponentScan
@WebFilter(urlPatterns = "/*", filterName = "crosFilter")
public class CrosFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletResponse res = (HttpServletResponse) response;
HttpServletRequest req = (HttpServletRequest) request;
res.addHeader("Access-Control-Allow-Origin", req.getHeader("Origin"));
res.addHeader("Access-Control-Allow-Methods", req.getHeader("Access-Control-Request-Method"));
// 带cookie时,需要的字段
res.addHeader("Access-Control-Allow-Credentials","true");
// 非简单请求,需要加上这句.支持所有自定义头
res.addHeader("Access-Control-Allow-Headers", req.getHeader("Access-Control-Request-Headers"));
// 告诉浏览器在1h内可以缓存这段信息,不用再发送预检命令。单位:s。
// 没有这句话,非简单请求的Method是OPTIONS
res.addHeader("Access-Control-Max-Age", "3600");
chain.doFilter(request, response);
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void destroy() {
}
}
在springboot项目中我遇到了个问题,后台我加入filter后,请求在浏览器端还是报错。经过排查,发现在页面的测试方法中我用了没注明请求方式的ajax,在后台明确是@GetMapping请求,修改后,浏览器不再报错。
问题3:是不是所有请求都是先执行后判断?
不是,简单请求是先执行后判断,非简单请求是先判断后执行。
什么是简单请求、非简单请求


这两种请求在跨域上的差别:非简单请求在filter中加上需要加上(参考上面filter)
res.addHeader("Access-Control-Allow-Headers", "Content-Type");
res.addHeader("Access-Control-Max-Age", "3600");
带Cookie的跨域
在服务端filter中:另一种写法
res.addHeader("Access-Control-Allow-Origin", "*");
这种写法存在的问题是,当请求带cookie时,浏览器会报错。
带cookie请求,不要忘了filter中加入下面这句
res.addHeader("Access-Control-Allow-Credentials","true");
cookie是被调用方的cookie!!
带自定义头的跨域
//支持所有自定义头
res.addHeader("Access-Control-Allow-Headers", req.getHeader("Access-Control-Request-Headers"));
2..被调用方解决---nginx解决方案(nginx配置)
上述filter就是基于被调用方的tomcat处理跨域。在讲解nginx配置之前,了解一下,虚拟主机的概念。虚拟主机,是多个域名指向同一个服务器,服务器根据不同的域名把请求转发到不同的应用服务器,感觉有多个主机,实际上只有一个主机。比较官方的说法:
虚拟主机(Virtual Host Virtual Server)是使用特殊的软硬件技术,把一台计算机主机分成一台台"虚拟"的主机,每一台虚拟主机都具有独立的域名和IP地址(或共享的IP地址),具有完整的Internet服务器功能。在同一台硬件、同一个操作系统上,运行着为多个用户打开的不同的服务器程序,互不干扰;而各个用户拥有自己的一部分系统资源(IP地址、文件存储空间、内存、CPU时间等)。虚拟主机之间完全独立, 在外界看来, 每一台虚拟主机和一台独立的主机的表现完全一样。
nginx配置
1.打开C:\Windows\System32\drivers\etc\hosts
在后面填上一句:
127.0.0.1 wj.com
表示被调用方的域名
2.在nginx的文件夹conf新建一个名为vhost的文件夹(在vhost文件夹用来放置虚拟主机的配置文件)

3.在conf文件夹的文件nginx.conf中添加

意思是要nginx载入这个目录下的conf文件。
4.在vhost下新建一个名为wj.com.conf的文件,文件中用nginx的语法写上:
server{
liaten 80;
server_name wj.com
location /{
proxy_pass http://localhost:8080/;
}
}
location 这句的意思是:把所有的请求都转到nginx的8080
5.配置完成后测试一下:

测试成功
6.启动nginx
![]()

去掉filter后,发现

wj.com.conf的文件中再加入:(注意if后有一个空格)
server{
listen 80;
server_name wj.com
location /{
proxy_pass http://localhost:8080/;
add_header Access-Control-Allow-Methods *;
add_header Access-Control-Max-Age 3600;
add_header Access-Control-Allow-Credentials true;
add_header Access-Control-Allow-Origin $http_origin;
add_header Access-Control-Allow-Headers $http_access_control_request_headers;
if ($request_method = OPTIONS){
return 200;
}
}
}
再测试一下编写wj.com.conf是否正确,下面成功

重新载入:
![]()
修改js测试的请求被调用方的路径为
var base = "http://wj.com/test";
885

被折叠的 条评论
为什么被折叠?



