什么是跨域
不同域名之间的资源访问
解决方法
JSONP,CROS
JSONP
原理:html带src属性的标签都可以跨域引用,jsonp通过写入和读取src文件内容来实现跨域。
用法
前端:
$.ajax({
type: 'GET',
url: captchaUrl,
dataType:'jsonp',
jsonp:'jsoncallback',
success: function(res){
$('#captcha').attr('src', res.url);
}
});
后端:
$jsoncallback = Yii::$app->request->get('jsoncallback', '');
if ($jsoncallback) {
Yii::$app->response->format = Response::FORMAT_JSONP;
$result = ['callback' => $jsoncallback, 'data' => $result];
}
- 优点:
支持较旧的浏览器
可以向不支持CORS的网站请求数据
- 缺点:
只支持get请求,导致传输文本长度受限
CROS
原理:请求header添加Access-Control-Allow-Origin相关属性
用法:
前端
$.ajax({
type:"POST",
url: url,
data: data,
xhrFields: {
withCredentials: true //需要写入cookie时设置为true,后端也要相应设置
},
crossDomain: true, //允许跨域
success:function(res){
success(res);
},
error: function(res){
error(res);
}
})
后端
设置header里的cros属性,下面是yii2的方法
public function behaviors()
{
$behaviors = parent::behaviors();
$behaviors["cors"] = [
'class' => Cors::className(),
'cors' => [
'Origin' => ['http://www.xxxxxx.com', ' //允许的域名,设置为'*'表示全部允许
'Access-Control-Request-Method' => ['POST', 'GET'], //允许的请求方式
'Access-Control-Allow-Credentials' => true, //需要写入cookie的时候要设置为true,前端也要相应设置
],
];
return $behaviors;
}
写入cookie时,如果是简单请求,可能有第一次请求无法写入,第二次请求才能写入的问题,需要进一步实验。
深入原理请参考:
http://www.ruanyifeng.com/blog/2016/04/cors.html
图片的跨域问题
首先图片受到url长度限制不能使用get请求传输,所以不能使用jsonp方式跨域。
如果遇到不支持cros的浏览器要跨域图片可以使用flash方式跨域,webuploader,ueditor等都支持配置使用swf文件进行图片传输。
服务器web目录要添加一个跨域文件crossdomain.xml,内容如下:
简单请求和复杂请求
简单请求response直接添加跨域信息
Access-Control-Allow-Origin: http://api.xxx.com
Access-Control-Allow-Credentials: true(可选)
Access-Control-Expose-Headers: FooBar(可选)
复杂请求会有一次OPTIONS预请求,在预请求中返回:
Access-Control-Allow-Origin: http://api.xxx.com
Access-Control-Allow-Methods: GET, POST, PUT
Access-Control-Allow-Headers: X-Custom-Header
Access-Control-Allow-Credentials: true
Access-Control-Max-Age: 86400 (缓存时间单位秒,在时间内再次访问该接口就不会有options预请求了)
然后再进行正式请求,返回内容和简单请求一样
laravel框架cros跨域实现:
laravel路由区分请求方式,options预请求要单独处理。目前自己写了一个中间件实现跨域。
header('Origin');
if (in_array($origin, $allowOrigins)) {
if ($request->isMethod('OPTIONS')) {
$response->header('Access-Control-Allow-Origin',$origin);
// $response->header('Access-Control-Allow-Credentials','true');
$response->header('Access-Control-Allow-Methods','POST, GET, PUT, DELETE');
$response->header('Access-Control-Allow-Headers','Content-Type,Authorization');
$response->header('Access-Control-Max-Age','86400');
}else{
$response->header('Access-Control-Allow-Origin', $origin);
// $response->header('Access-Control-Allow-Credentials','true');
}
}
return $response;
}
}