跨域javascript
1、跨域是什么?为何会存在跨域?前端
①、广义的定义:一个域下的文档或脚本试图去请求另外一个域下的资源,如:www.baidu.com去请求www.google.com下的资源;vue
如相似:资源跳转(<a>标签连接、重定向、表单提交)、资源嵌入(<link>、<script>、<img>、<frame>等DOM标签)、脚本请求(JS发起的Ajax请求等)java
狭义的定义:由浏览器同源策略限制的一类请求场景,这也是咱们一般说的跨域问题node
②、由于浏览器的“同源策略”nginx
①、什么是同源策略?为何要有同源策略?ajax
a、同源策略/SOP(Same origin policy)是一种约定,由Netscape公司1995年引入浏览器,它是浏览器最核心也最基本的安全功能,若是缺乏了同源策略,浏览器很容易受到XSS、CSFR等攻击。spring
所谓同源是指"协议+域名+端口"三者相同,即使两个不一样的域名指向同一个ip地址,也非同源。json
b、浏览器施加的安全限制后端
2、跨域的解决方式?
一、 经过jsonp跨域
二、 document.domain + iframe跨域
三、 location.hash + iframe
四、 window.name + iframe跨域
五、 postMessage跨域
六、 跨域资源共享(CORS)
七、 nginx代理跨域
八、 nodejs中间件代理跨域
九、 WebSocket协议跨域
此处就介绍一下:JSONP 跟 CORS 这两种方式
①、JSONP
扩展:JSONP 全称是JSON with Padding,是为了解决跨域请求资源而产生的解决方案,是一种依靠开发人员创造出的一种非官方跨域数据交互协议。
JSON是描述信息的格式,JSONP是信息传递双方约定的方法。
前端代码:
a、原生方式:
<script type="text/javascript" src="http://localhost:8080/api/test?callback=test"></script>
<script type="text/javascript">
function test(arg){
//.....
}
</script>
服务端返回以下(返回时即执行全局函数):test({"status": true, "user": "admin"})
b、query ajax:
$.ajax({ url: 'http://localhost.com:8080/login', type: 'get', dataType: 'jsonp', // 请求方式为jsonp jsonpCallback: "test", // 自定义回调函数名 data: {} });
c、vue.js:
this.$http.jsonp('http://www.domain2.com:8080/login',
{ params: {}, jsonp: 'test' }
).then((res) => { console.log(res); })
后端代码:
String data = new Gson().toJson(...);
PrintWriter out = response.getWriter();
out.write(callback + "(" + data + ")"); Java后端实现:
String callback = request.getParameter("callback");
Node.js后端实现:
var querystring = require('querystring'); var http = require('http'); var server = http.createServer(); server.on('request', function(req, res) { var params = qs.parse(req.url.split('?')[1]); var fn = params.callback; // jsonp返回设置 res.writeHead(200, { 'Content-Type': 'text/javascript' }); res.write(fn + '(' + JSON.stringify(params) + ')'); res.end(); }); server.listen('8080'); console.log('Server is running at port 8080...');
②、CORS
普通跨域请求:只服务端设置Access-Control-Allow-Origin便可,前端无须设置。
带cookie请求:先后端都须要设置字段,另外需注意:所带cookie为跨域请求接口所在域的cookie,而非当前页。
目前,全部浏览器都支持该功能(IE8+:IE8/9须要使用XDomainRequest对象来支持CORS)),CORS也已经成为主流的跨域解决方案。
前端代码:
a、原生ajax
// 前端设置是否带cookie
xhr.withCredentials = true;
示例代码:
var xhr = new XMLHttpRequest(); // IE8/9需用window.XDomainRequest兼容
// 前端设置是否带cookie
xhr.withCredentials = true;
xhr.open('post', 'http://www.domain2.com:8080/login', true);
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
xhr.send('user=admin');
xhr.onreadystatechange = function() {
if (xhr.readyState == 4 && xhr.status == 200) {
alert(xhr.responseText);
}
};
b、JQuery ajax
$.ajax({
...
xhrFields: {
withCredentials: true // 前端设置是否带cookie
},
crossDomain: true, // 会让请求头中包含跨域的额外信息,但不会含cookie
...
});
c、VUE
框架在vue-resource封装的ajax组件中加入如下代码:
Vue.http.options.credentials = true
服务端设置:
若后端设置成功,前端浏览器控制台则不会出现跨域报错信息,反之,说明没设成功。
a、Java后台:
response.setHeader("Access-Control-Allow-Origin", "http://localhost.com"); // 如有端口需写全(协议+域名+端口)
response.setHeader("Access-Control-Allow-Credentials", "true");
b、Nodejs后台示例:
var http = require('http');
var server = http.createServer();
var qs = require('querystring');
server.on('request', function(req, res) {
var postData = '';
// 数据块接收中
req.addListener('data', function(chunk) {
postData += chunk;
});
// 数据接收完毕
req.addListener('end', function() {
postData = qs.parse(postData);
// 跨域后台设置
res.writeHead(200, {
'Access-Control-Allow-Credentials': 'true', // 后端容许发送Cookie
'Access-Control-Allow-Origin': 'http://www.domain1.com', // 容许访问的域(协议+域名+端口)
'Set-Cookie': 'l=a123456;Path=/;Domain=www.domain2.com;HttpOnly' // HttpOnly:脚本没法读取cookie
});
res.write(JSON.stringify(postData));
res.end();
});
});
server.listen('8080');
console.log('Server is running at port 8080...');
CORS高级应用:
springmvc4.2版本增长了对cors的支持。
目前我所作的项目基本都是springboot进行开发,因此我这里贴下在springboot中的使用。
@Configuration public class MyWebAppConfigurer extends WebMvcConfigurerAdapter{ @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**"); }
能够在addMapping中配置咱们的路径。/**表明全部路径。
固然也能够修改其它属性
@Configuration public class MyWebAppConfigurer extends WebMvcConfigurerAdapter{ @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/api/**") .allowedOrigins("http://192.168.1.97") .allowedMethods("GET", "POST") .allowCredentials(false).maxAge(3600); }
以上两种,都是针对全局配置,若是你想作到更细致也可使用@CrossOrigin这个注解在controller类中使用。
@CrossOrigin(origins = "http://192.168.1.97:8080", maxAge = 3600) @RequestMapping("rest_index") @RestController public class IndexController{
这样就能够指定该controller中全部方法都能处理来自http:19.168.1.97:8080中的请求。