一、概述
1、跨域说明
一个域名地址由以下几个部分组成:
http://www.aaa.com:8080/s?ie=UTF-8&wd=SpringBoot
- 协议:http
- 域名:子域名www,主域名aaa.com
- 端口:8080
从一个域名的网页去请求另一个域名的资源时,协议,域名,端口任意不同,都会出现跨域问题。
http://www.aaa.com:8080——>http://www.aaa.com:8080:同域访问
http://www.aaa.com:8080——>http://www.bbb.com:8080:跨域访问
2、实现跨域
cors
和jsonp
都是用于解决跨域问题,当两个页面的协议、域名、端口号中有一个不一致时就存在了跨域,一旦出现跨域,浏览器发送跨域请求后,请求回来的数据都会被浏览器所拦截。
注意:浏览器允许发起跨域请求,但是,跨域请求回来的数据,会被浏览器拦截,无法被页面获取到。
如何实现跨域数据请求?
现下实现跨域数据请求,最主要的两种解决方案分别是 JSONP
和 CORS
。
JSONP
: 出现的早,兼容性好(兼容低版本 IE )。是前端程序员为了解决跨域问题,被迫想出来的一种 临时解决方案,最主要的缺点 是只支持GET
请求,不支持POST
请求。CORS
: 出现的较晚,它是W3C
标准,属于跨域Ajax
请求的根本解决方案。支持GET
和POST
请 求。缺点 是不兼容某些低版本的浏览器。
二、JSONP
简介
1、什么是JSONP
JSONP
(JSON with Padding
) 是 JSON
的一种“使用模式”,可用于解决主流浏览器的跨域数据访问的问题。
2、JSONP
的实现原理
概念:浏览器端通过 <script>
标签的 src
属性,请求服务器上的数据,同时,服务器返回一个函数的调用。这种请求数据的方式叫做 JSONP
3、特点
JSONP
不属于真正的 Ajax
请求,因为它没有使用 XMLHttpRequest
这个对象
JSONP
仅支持 GET 请求,不支持 POST、PUT、DELETE 等请求
三、JSONP
跨域
jsonp
就是能够跨域请求数据。
利用 src
可以跨域加载 js
代码。这样就可以取到js
的代码,然后,在前端执行js
代码即可。
在后端我们只要动态生成js
代码就好了。
1、案例一(js实现)
(1)前端代码
利用script标签,加载动态生成的js代码,js会回调相应方法,并且将数据传递给回调方法。
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>jsonp实现案例</title>
<script type="text/javascript">
var flightHandler = function(data){
alert('你查询的航班结果是:票价 ' + data.price + ' 元,' + '余票 ' + data.tickets + ' 张。');
};
// 提供jsonp服务的url地址(不管是什么类型的地址,最终生成的返回值都是一段javascript代码)
var url = "http://ip/WxServlet/jsonp2.js?callback=flightHandler";
// 创建script标签,设置其属性
var script = document.createElement('script');
script.setAttribute('src', url);
// 把script标签加入head,此时调用开始
document.getElementsByTagName('head')[0].appendChild(script);
</script>
</head>
<body>
</body>
</html>
(2)后端代码
动态生成js代码,代码里放置一个回调方法。
String code = req.getParameter("code");
String collback = req.getParameter("callback");
System.out.println(code+collback);
String str = "flightHandler({\"code\": \"CA1998\",\"price\": 1780,\"tickets\": 5});";
resp.getWriter().append(str);
2、案例二(jquery实现)
(1)前端代码
接下来看下使用jquery的jsonp来实现跨域访问,例子如下:
$(function(){
$.ajax({
type: "get",
async: false,
url: "http://ip/WxServlet/jsonp2.js",
dataType: "jsonp",
jsonp: "callback",
jsonpCallback:"flightHandler",
success: function(json){
alert('您查询到航班信息:票价: ' + json.price + ' 元,余票: ' + json.tickets + ' 张。');
},
error: function(){
alert('fail');
}
});
});
(2)后端代码
动态生成js代码,代码里放置一个回调方法。
String code = req.getParameter("code");
String collback = req.getParameter("callback");
System.out.println(code+collback);
String str = "flightHandler({\"code\": \"CA1998\",\"price\": 1780,\"tickets\": 5});";
resp.getWriter().append(str);
四、CORS
简介
1、什么是CORS
CORS
(跨域资源共享) 由一系列 HTTP 响应头组成,这些 HTTP 响应头决定浏览器 是否阻止前端JS
代码跨域获取资源- 浏览器的同源安全策略默认会阻止网页“跨域”获取资源。但如果接口服务器配置了
CORS
相关的 HTTP 响应头,就可以解除浏览器端的跨域访问限制
2、CORS
概念
CORS
(Cross-Origin Resource Sharing
跨源资源共享)
当一个请求url的协议
、域名
、端口
三者之间任意一与当前页面地址不同即为跨域。
在日常的项目开发时会不可避免的需要进行跨域操作,而在实际进行跨域请求时,经常会遇到类似 No 'Access-Control-Allow-Origin' header is present on the requested resource.
这样的报错。这样的错误,一般是由于CORS
跨域验证机制设置不正确导致的。
五、CORS
案例
1、普通web项目
(1)添加过滤器
import javax.servlet.*;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class CORSFilter implements Filter {
public void init(FilterConfig filterConfig) throws ServletException {
}
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletResponse httpResponse = (HttpServletResponse) servletResponse;
//*表示允许所有域名跨域
httpResponse.addHeader("Access-Control-Allow-Origin", "*");
httpResponse.addHeader("Access-Control-Allow-Headers",
"Origin, X-Requested-With, Content-Type, Accept");
//允许跨域的Http方法
httpResponse.addHeader("Access-Control-Allow-Methods", "GET,POST,PUT,DELETE");
filterChain.doFilter(servletRequest, servletResponse);
}
public void destroy() {
}
}
(2)web.xml配置
<!--为了允许跨域访问-->
<filter>
<filter-name>CorsFilter</filter-name>
<filter-class>org.du.personalsitemock.mockutil.CORSFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>CorsFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
(3)前端代码
$.ajax({
url: 'http://xxxx/test/cors?name=tom',
type: 'post',
data: '',
// 默认情况下,标准的跨域请求是不会发送cookie的
xhrFields: {
withCredentials: true
},
success: function(rs) {
}
})
2、Spring项目(@CrossOrigin注解)
在类或方法上添加注解即可,@CrossOrigin(origins = "*", allowCredentials = "true")
。
(1)后端代码
@RestController
@CrossOrigin(origins = "*", allowCredentials = "true")
public class TestController {
@RequestMapping(value = "test/cors")
public Object cors() {
try {
Map<String, Object> map = getParameterMap();
System.out.println(map.toString());
return output(map);
} catch (Exception e) {
e.printStackTrace();
return output("9999", "错误", e.getMessage());
}
}
}
(2)前端代码
$.ajax({
url: 'http://xxxx/test/cors?name=tom',
type: 'post',
data: '',
// 默认情况下,标准的跨域请求是不会发送cookie的
xhrFields: {
withCredentials: true
},
success: function(rs) {
}
})
3、Spring项目(添加全局过滤器)
若项目中所有接口都允许跨域访问,可增加全局过滤器允许跨域访问。
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
@Configuration
public class CorsConfig {
// 当前跨域请求最大有效时长。这里默认1天
private static final long MAX_AGE = 24 * 60 * 60;
@Bean
public CorsFilter corsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration corsConfiguration = new CorsConfiguration();
corsConfiguration.addAllowedOrigin("*"); // 1 设置访问源地址,或者http://localhost:7060
corsConfiguration.addAllowedHeader("*"); // 2 设置访问源请求头
corsConfiguration.addAllowedMethod("*"); // 3 设置访问源请求方法,或设置为"GET", "POST", "DELETE", "PUT"
corsConfiguration.setMaxAge(MAX_AGE);
source.registerCorsConfiguration("/**", corsConfiguration); // 4 对接口配置跨域设置
return new CorsFilter(source);
}
}
4、Spring项目(实现WebMvcConfigurer)
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class WebConfig implements WebMvcConfigurer {
// 当前跨域请求最大有效时长。这里默认1天
private static final long MAX_AGE = 24 * 60 * 60;
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*")
.allowedMethods("*")
.allowedHeaders("*")
.maxAge(MAX_AGE);
}
}
5、Nginx解决跨域
如果项目中有使用Nginx来转发请求,那也可以交由Nginx来解决跨域,但是有一点需要注意:Nginx解决跨域和后端解决跨域最好只保留一个,两种混用会出现很多奇怪的问题。
下面是nginx.conf文件解决跨域的相关配置:
server {
listen 80;
server_name localhost;
location / {
if ($request_method = 'OPTIONS') {
add_header Access-Control-Allow-Origin 'http://localhost:7060';
add_header Access-Control-Allow-Headers '*';
add_header Access-Control-Allow-Methods '*';
add_header Access-Control-Allow-Credentials 'true';
return 204;
}
if ($request_method != 'OPTIONS') {
add_header Access-Control-Allow-Origin 'http://localhost:7060' always;
add_header Access-Control-Allow-Credentials 'true';
}
proxy_pass http://localhost:59200;
}
}
6、参考
CrossOrigin注解没有生效,解决方案集合
https://blog.csdn.net/suxiexingchen/article/details/104861803
CrossOrigin注解没有生效,解决方案集合
https://suxiexingchen.github.io/2020/03/14/36/
ajax携带cookie的两种方式
https://www.cnblogs.com/lgl1209/p/11527080.html
六、参考
9种常见的前端跨域解决方案(详解)
https://www.imooc.com/article/291931
CORS和JSONP的区别,如何解决跨域问题?
https://blog.csdn.net/SunFlower914/article/details/120691847
java web服务器实现跨域访问
https://www.iteye.com/blog/yjph83-2253863