CROS的跨域请求
当协议、子域名、主域名、端口号中任何一个不相同时,都算作不同域
跨域请求是指一个请求通过请求一个服务得到了响应,这个响应中又向另一个服务发送了请求。
例如:请求8888端口的此html页面,这个页面中有一端js代码向8887端口发送了请求。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>Page Title</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
</body>
<script>
var xhr = new XMLHttpRequest()
xhr.open('GET', 'http://127.0.0.1:8887/') //向8887端口发送请求
xhr.send()
</script>
</html>
正常情况下,这个跨域请求会被浏览器拦截并报错(8887端口服务依然会处理请求)。
使用链接的方式进行跨域请求是不会被拦截的:
这些链接请求不会被拦截
<script src='http://127.0.0.1:8887/' />
<link src='http://127.0.0.1:8887/' />
如果想要允许这种跨域请求,可以在服务器返回response头信息中添加以下字段来限定哪些地址的跨域请求可以被允许:(8887端口服务返回头信息)
http.createServer(function (request, response){
console.log('request come', request.url)
response.writeHead(200, {
'Access-Control-Allow-Origin' : '*', //1.设置任何地址都可以访问这个服务
'Access-Control-Allow-Origin' : 'http://baidu.com' //2.设置只允许百度来跨域访问这个服务
})
response.end('123')
}).listen(8887)
修改后再次跨域请求的结果:
CROS的预请求
在跨域请求时,默认允许(这里的允许指不需要预请求验证)的方法只有GET、HEAD、POST,对于其余的方法请求,浏览器要先对服务器进行预请求再进行处理。
默认允许的Content-Type为:text/plain,multipart/form-data,application/x-www-form-urlenncoded
其余限制:
- 请求头限制(主要)
- XMLHttpRequestUpload对象没有注册任何事件监听器
- 请求中没有使用ReadableStream对象
将测试html页面中的script代码改为PUT操作(之前的GET操作不用预请求):
<script>
fetch('http://localhost:8887/',{
method : 'PUT',
headers : { //加一个自定义的头信息
'X-Test-Cors' : '123'
}
})
</script>
8887端口服务改动:
response.writeHead(200, {
'Access-Control-Allow-Origin' : '*', //任何页面都可以访问这个服务
// 'Access-Control-Allow-Origin' : 'http://baidu.com', //只允许百度来访问这个服务
'Access-Control-Allow-Headers' : 'X-Test-Cors', //允许含有这个头信息的request请求服务
'Access-Control-Allow-Methods' : 'POST,PUT,DELETE',
'Access-Control-Max-Age' : '1000' //1000秒之内,上面的请求,不需要预请求,可以直接发送请求
})
在跨域请求被允许后,再次发送PUT跨域请求时,会先对服务器发起一个预请求(HTTP首行中Request Method为OPTIONS),之后再进行具体method的请求。从图中可以看出,实际只有两次请求,但是在NetWork中发送了三次请求:
演示用例代码:
8888端口server:可以使用node.js 的node命令:node server.js来启动server
const http = require('http')
const fs = require('fs')
http.createServer(function (request, response){
console.log('request come', request.url)
const html = fs.readFileSync('test.html', 'utf8')//读取html页面,按utf-8编码
response.writeHead(200, {
'Content-Type' : 'text/html'
})
response.end(html)
}).listen(8888)
console.log('server lisening on 8888')
8887端口server:
http.createServer(function (request, response){
console.log('request come', request.url)
response.writeHead(200, {
'Access-Control-Allow-Origin' : '*', //1.任何地址都可以访问这个服务
'Access-Control-Allow-Origin' : 'http://baidu.com' //2.只允许百度来访问这个服务
'Access-Control-Allow-Headers' : 'X-Test-Cors', //3.允许含有这个头信息的request请求服务
'Access-Control-Allow-Methods' : 'POST,PUT,DELETE',//4.允许POST、PUT、DELETE方法的跨域请求
'Access-Control-Max-Age' : '1000' //5.1000秒之内,上面的请求,不需要进行预请求,可以直接发送请求
})
response.end('123')
}).listen(8887)
测试的html页面:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>Page Title</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- <link rel="stylesheet" type="text/css" media="screen" href="main.css">
<script src="main.js"></script> -->
</head>
<body>
</body>
<script>
var xhr = new XMLHttpRequest()
xhr.open('GET', 'http://127.0.0.1:8887/')
xhr.send()
</script>
<!-- <script src="http://127.0.0.1:8887/">
//使用链接的方式进行跨域请求不会被拦截,不需要设置Access-Control-Allow-Origin
//这个拦截是由浏览器发起的,服务器总是可以收到请求,只是浏览器会报错。
</script> -->
<!-- <script> //这个用来测试8887服务中 3 和 4 的设置
fetch('http://localhost:8887/',{
method : 'PUT',
headers : {
'X-Test-Cors' : '123'
}
})
</script> -->
</html>