同源与跨域
前后端分离就会出现跨域问题。不用在html语言中嵌入jsp、asp、ejr等,而是混入html中直接操作数据库、获取数据。这是一种前后端分离开发的模式。前后端的通信是基于Ajax技术的,这也是Javascript最重要的技术之一。
为了维护浏览器的安全,指定了同源政策也就是域名、协议、港口均相同的才能进行访问,当页面在执行一个脚本时会检查访问的资源是否同源,如果非同源,那么在请求数据时,就会被浏览器拦截。
然而,前端和后端单独开发时使用的软件可能不同,这可能会导致三者之间的不一致。 (最常见的是端口)
http://localhost:8080/index.html
http://locahost/user //(默认80)
//端口不同
http://abc.com
http://abd.com/post/
//域名不同
http://abc.com
https://abc.com
//协议不同
跨域是指请求URL的协议、域名、端口有一个与当前页面URL不同,则为跨域。实现跨域访问的技术有很多,比如JSONP、flash、iframe、跨域资源共享(Cors)、nginx代理跨域、nodejs中间件代理跨域、WebSocket协议跨域等。
Cors解决跨域问题的原理
CORS定义一种跨域访问的机制,可以让AJAX实现跨域访问。CORS 允许一个域上的网络应用向另一个域提交跨域 AJAX 请求。
如图就是跨域导致请求不成功:
可以看到请求的网址端口收80,响应端口收8080(Origin)
-
http请求头
Origin: 普通的HTTP请求也会带有,在CORS中专门作为Origin信息供后端比对,表明来源域。
Access-Control-Request-Method: 接下来请求的方法,例如PUT, DELETE等等
Access-Control-Request-Headers: 自定义的头部,所有用setRequestHeader方法设置的头部都将会以逗号隔开的形式包含在这个头中。 -
请求头中访问控制请求方法表示请求的方法,例如PUT, DELETE等等
**Access-Control-Request-Headers:**自定义的头部,所有用setRequestHeader方法设置的头部都将会以逗号隔开的形式包含在这个头中。 -
http响应头
响应也是通过http协议封装的,其中origin字段表明跨域请求的来源。然后服务器处理完请求之后,会再返回结果中加上如下控制字段。 -
访问控制允许来源: 允许跨域访问的域,可以是一个域的列表,也可以是通配符"*"。这里要注意Origin规则只对域名有效,并不会对子目录有效。即http://foo.example/subdir/ 是无效的。但是不同子域名需要分开设置,这里的规则可以参照同源策略
访问控制允许凭证: 是否允许请求带有验证信息,
访问控制公开标头: 允许脚本访问的响应头
访问控制最大年龄: 缓存此次请求的秒数。在这个时间范围内,所有同类型的请求都将不再发送预检请求而是直接使用此次返回的头作为判断依据,非常有用,大幅优化请求次数
访问控制允许方法: 允许使用的请求方法,以逗号隔开
访问控制允许标头: 允许自定义的头部,以逗号隔开,大小写不敏感
JavaWeb解决跨域问题
根据CORS原理,只需添加Origin中允许访问的域名即可。
- 编写Filter修改Origin:
import javax.servlet.*;
import javax.servlet.annotation.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
//自定义
@WebFilter("/*") //这里是注解,习惯web.xml配置的见下
public class allFilter implements Filter {
public void init(FilterConfig config) throws ServletException {
}
public void destroy() {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException {
HttpServletResponse res = (HttpServletResponse)response;
res.setHeader("Access-Control-Allow-Origin", "http://localhost:8080");
res.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
res.setHeader("Access-Control-Max-Age", "3600");
res.setHeader("Access-Control-Allow-Headers", "x-requested-with");
chain.doFilter(request, response); //注意最后一定要放行
}
}
核心:添加上允许访问的域名
```js
res.setHeader("Access-Control-Allow-Origin", "http://localhost:8080");
webxml配置
```java
<filter>
<filter-name>CORSFilter</filter-name> //过滤器名称
<filter-class>com.grain.filter.CORSFilter</filter-class> //过滤器所在项目路径
</filter>
<filter-mapping>
<filter-name>CORSFilter</filter-name>
<url-pattern>/*</url-pattern> //允许那些域名访问 /* 表示所有
</filter-mapping>
- web.xml配置文件解决跨域
下载cors-filter-1.7.jar和java-property-utils-1.9.jar工具包然后在web.xml配置Filter文件,如下:
<filter>
<filter-name>CORS</filter-name>
<filter-class>com.thetransactioncompany.cors.CORSFilter</filter-class>
<init-param>
<param-name>cors.allowOrigin</param-name>
<param-value>*</param-value>
</init-param>
<init-param>
<param-name>cors.supportedMethods</param-name>
<param-value>GET,POST,HEAD,PUT,DELETE</param-value>
</init-param>
<init-param>
<param-name>cors.supportedHeaders</param-name>
<param-value>Accept,Origin,X-Requested-With,Content-Type,Last-Modified</param-value>
</init-param>
<init-param>
<param-name>cors.exposedHeaders</param-name>
<param-value>Set-Cookie</param-value>
</init-param>
<init-param>
<param-name>cors.supportsCredentials</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CORS</filter-name>
<url-pattern>/*</url-pattern> </filter-mapping>
它们都修改了 Origin 以允许跨域访问。
如果学习了Spring框架还会有更高级的方法,所以一起加油把!
科尔斯官方网站
其他的跨域问题@黛米讲的很全谢谢作者!