-
传送门:
- 1. JavaScript 教程 / 浏览器模型 / CORS 通信
- 2. CORS ajax跨域请求php简单完整案例一则
- 3. Content-Type 详解
- 4. OPTIONS预检请求
一、简单请求
- a.html(http://aaa.com/a.html)
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title></title>
</head>
<body>
<input type="button" id="btn" value="点击获取随机图片" onclick="getRandomPic()" />
<div class="demo"></div>
<script>
function getRandomPic() {
// ajax 向同域后端文件发出请求,接收数据
var xhr = new XMLHttpRequest();
xhr.open('GET', 'http://bbb.com/b.php?random=' + Math.random(), true);
xhr.onreadystatechange = function() {
if (this.readyState === 4) {
if ((this.status >= 200 && this.status < 300)
|| (this.status === 304)) {
var imgURL = this.responseText;
document.querySelector('.demo').innerHTML =
'<img src="' + imgURL + '" width=500 />';
} else {
console.log(new Error);
}
}
};
// 向服务器发出请求是否携带 Cookie(某些浏览器默认 false,某些则为 true)
xhr.withCredentials = true;
// 需要配合服务器设置 'Access-Control-Allow-Credentials: true' 字段
xhr.send(null);
}
</script>
</body>
</html>
- b.php(http://bbb.com/b.php)
<?php
// 指定允许访问的域名(必需)
header('Access-Control-Allow-Origin: http://aaa.com');
// 指定允许响应的类型(可选,除去这三种之外的,都是非简单请求)
header('Access-Control-Allow-Methods: POST, GET, HEAD');
// 指定是否允许携带 Cookie 发送请求(可选,默认 false)
header('Access-Control-Allow-Credentials: true');
# 需要配合客服端的 XMLHttpRequest.withCredentials = true; 属性
// 告知服务端以 HTML文档标记 格式处理请求数据
header('Content-type: text/html; charset=utf-8');
// 发送过来的随机数
$random = $_GET['random'];
// 输出一个带有随机参数的图片地址,防止地址被缓存而固定为一张图片
echo 'https://uploadbeta.com/api/pictures/random/?key=BingEverydayWallpaperPicture&random='.$random;
?>
二、非简单请求
1. OPTIONS 预检请求
模拟:ajax向服务器发送的请求中,携带 Content-Type 字段的类型为 application/json
【b.php 可空白,不进行任何处理,此处只是模拟预检请求】
这是由于 a.html 的 ajax 中设置了 xhr.setRequestHeader(‘Content-Type’, ‘application/json’);
浏览器将该请求识别为了非简单请求。
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title></title>
</head>
<body>
<script>
var xhr = new XMLHttpRequest();
xhr.open('POST', 'http://bbb.com/b.php', true);
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.send(null);
</script>
</body>
</html>
2. 示例
- a.html(http://aaa.com/a.html)
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title></title>
</head>
<body>
<script>
// 转为JSON字符串(POST、GET请求会强制转换为字符串类型,这里需要处理下)
var obj = JSON.stringify({
name: '张三',
age: 14,
domain: 'http://aaa.com'
});
var xhr = new XMLHttpRequest();
xhr.open('POST', 'http://bbb.com/bb.php', true);
xhr.onreadystatechange = function() {
if (this.readyState === 4) {
if ((this.status >= 200 && this.status < 300)
|| (this.status === 304)) {
console.log(this.responseText);
} else {
console.log(new Error);
}
}
};
// 这是POST请求通常设置的字段信息(必需)
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
// 注意,因为还需要再设置多一个字段,所以结尾不应该有分号
// 向服务器发送json数据时需要设置的字段
xhr.setRequestHeader('Content-Type', 'application/json; charset=utf-8');
// 虽然也可以直接使用上面字段,但是设置本字段会触发"预检"OPTIONS请求
// 或者写在一起,逗号隔开
// xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded, application/json; charset=utf-8');
xhr.send('data=' + obj);
</script>
</body>
</html>
- b.php(http://bbb.com/b.php)
<?php
// 指定允许访问的域名(必需)
header('Access-Control-Allow-Origin: http://aaa.com');
// 指定允许响应的类型(必需)
# 为了避免多次“预检”请求,返回的是所有支持的方法
header('Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS, PATCH, HEAD');
// 表明服务器支持的所有头信息字段,不限于浏览器在“预检”中请求的字段(必需)
# 对应在ajax中设置的setRequestHeader('Content-Type', ...);
header('Access-Control-Allow-Headers: Content-Type, Content-Length, Authorization, Accept, X-Requested-With'); // 或者 *
// 指定本次预检请求的有效期,单位为秒(可选)
header('Access-Control-Max-Age: 1');
// 处理传递过来的JSON字符串,转为PHP数组
$json = json_decode($_POST['data'], true);
echo 'Hello '.$json['name'].', 该消息来自: http://bbb.com';
?>