跨域对接方法总结
一、后台跨域-V1
1. 后台设置
- 配置过滤器,为所有的响应头都加上 下面四个字段
-
Access-Control-Allow-Origin: '具体源' :允许通过跨域访问后台服务器的源。如果需要使用section来标示不同的会话,则需要前端设置允许cookie(因为浏览器是通过发送cookie中相关的ID ( JSESSIONID )来标识的),并且后台的 Access-Control-Allow-Origin 不可以设置为通配符 ‘ * ’,需要指定一个明确的域名,可以是 null (即通过本地文件 file:// 发送的请求), 然后后台动态的获取request 的 origin 去设置 Access-Control-Allow-Origin 。
-
Access-Control-Allow-Methods: "POST, ..." :该字段是必须的,用来列出浏览器的CORS请求会用到哪些HTTP方法
-
Access-Control-Allow-Headers: "Content-Type, ...":该字段是一个逗号分隔的字符串,指定浏览器CORS请求会额外发送的头信息字段
-
Access-Control-Max-Age: '3600':规定在多长时间内不需要再发生 预检请求 就能跨域访问
// spring 写法
package gdut.qg.utils;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* Created by logan on 2017/5/23.
*/
public class CORSFilter implements Filter {
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
String Origin = request.getHeader("Origin");
/* 此处通过动态设置运行跨域访问的源 */
response.setHeader("Access-Control-Allow-Origin", Origin);
response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
response.setHeader("Access-Control-Max-Age", "36000");
response.setHeader("Access-Control-Allow-Credentials", "true");
response.addHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
chain.doFilter(req, res);
}
public void init(FilterConfig filterConfig) {}
public void destroy() {}
}
2. 前端设置
- 如果需要保持将两次请求维持在同一个会话中(即后台需要用到 session 来识别用户),需要保持Request Cookies 中的 JSESSIONID 的值在两次请求中不变,即需要在请求时允许跨域请求携带 Cookie
- 原生
//原生
var xhr = new XMLHttpRequest();
xhr.open('GET', url);
xhr.withCredentials = true; //允许跨域请求携带 Cookie
xhr.send();
- jQuery
// jQuery
$.ajax({
type: "post",
url: "xxx",
data: data,
xhrFields: {
withCredentials: true //允许跨域请求携带 Cookie
}
success: function(data) {
console.log(data)
},
});
二、后台跨域-V2
1. 后台设置
- 配置过滤器,为所有的响应头都加上 下面的字段
-
Access-Control-Allow-Origin: ' * ' :允许通过跨域访问后台服务器的源,如果设置为 * ,表示可以让任何源访问,当是这里需要再设置一个参数 Access-Control-Allow-Credentials 为 false,表明不允许携带 cookie 才可以
-
Access-Control-Allow-Methods: "POST, ..." :该字段是必须的,用来列出浏览器的CORS请求会用到哪些HTTP方法
-
Access-Control-Allow-Headers: "Content-Type, ...":该字段是一个逗号分隔的字符串,指定浏览器CORS请求会额外发送的头信息字段
-
Access-Control-Max-Age: '3600':规定在多长时间内不需要再发生 预检请求 就能跨域访问
-
Access-Control-Allow-Credentials : false : 不允许携带 cookie
2. 前端设置
- 设置 withCredentials 为 false
// jQuery
$.ajax({
type: "post",
url: "xxx",
data: data,
xhrFields: {
withCredentials: false //不允许跨域请求携带 Cookie
}
success: function(data) {
console.log(data)
},
});
// axios
import axios from 'axios'
axios.defaults.withCredentials = false //全局设置 withCredentials 为 false
export const IP = 'https://xxxxxxx.com/';
export const myAxios = axios.create({
baseURL: IP,
})
3. 缺点
- 由于不允许传cookie,所以无法把 section 通过 cookie 传到服务器,即后台获取不到section。所以无法记住登录状态,需要改为用 token 才行。
三、插件跨域
使用Google插件 :Allow-Control-Allow-Origin: *
1. 后台
不需要后台配置任何的响应头字段
2. 前端
直接写要访问的其他域的路径,跟平时使用没有区别。
3. 缺点
-
插件跨域后相当于在不同的会话框中,所以没有包含之前登录的 section,即后台获取不到section。
-
该插件会将请求的 origin 设置为 ”http: //evil.com“。
// 这是请求头携带的信息
Request Headers
OPTIONS /ExcellentCourses/admin/login HTTP/1.1
Host: 123.207.228.117
Connection: keep-alive
Access-Control-Request-Method: POST
Origin: http://evil.com/ //注意这里的origin已经被插件换了
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64)...
Access-Control-Request-Headers: content-type
Accept: */*
Accept-Encoding: gzip, deflate, sdch
Accept-Language: zh-CN,zh;q=0.8
四、代理跨域
1. 前端
- 如果使用Vue框架,可以使用 Vue-cli 的 proxyTable 配置
proxyTable: {
'/api': {
target: 'http://192.168.1.107:80',
changeOrigin: true,
pathRewrite: {
'^/api': '/'
}
}
},
// 把含有 api 的请求路径代理到 http://192.168.1.107:80/ 上。
//如 localhost:8080/api/add -> http://192.168.1.107:80/add
可配置 axios 来食用
import axios from 'axios'
IP = '/api';
myAxios = axios.create({
baseURL: IP
})
getAllTeachers() {
return new Promise((resolve, reject) => {
myAxios({
method: 'POST',
url: '/teacher/allTeachers'
}).then(function(res){
resolve(res.data)
}).catch(function(err){
reject(err)
})
})
}
2. 后台
-
不需要后台配置任何的响应头字段
-
session仍然可以使用
五、总结
-
使用第一种可以用到真实的线上环境,第二中可以配合token在真实线上使用,而第三种和第四种只是用于开发环境
-
如果后台不需要使用 section,并且之后整合前后代码是在同一个服务器上,则推荐使用第二种方式,因为这样前后都不要修该自己的代码,能缩短开发周期。
-
如果后台需要用到 section,并且之后整合前后代码是在同一个服务器上,则推荐使用第四种方式,前提是前端能使用 webpack 来配置代理服务器
-
如果需要跨域而前端又不能使用代理,则需要前后一起去配置有关CORS的请求头和响应头信息,不过这种方法当真正上线时也可以跨域,算是正统的方法。
六、参考
- 关于简单请求与非简单请求的跨域问题。跨域资源共享 CORS 详解
- 后台实现跨越。Spring MVC通过CROS协议解决跨域问题
- 跨域请求,关于后端session会话丢失的解决办法
- 浏览器 AJAX 跨域请求访问控制