1.什么是ajax跨域问题
简单来说,前台调用后台服务器接口的时候,如果接口不是同一个域的话 ,那么这个时候就会产生跨域问题,前端调用也会报错。
由于浏览器同源策略,凡是发送请求url的协议、域名、端口三者之间任意一与当前页面地址不同即为跨域
2.为什么会产生跨域问题
- 浏览器的限制
- 跨域(ip+端口 域名不同)
- XHR(XMLHttpRequest) 请求
以上三个条件都满足的话就会产生跨域
例如:
3.解决跨域问题的思路 - jsonp 通过动态创建script,存在诸多弊端
- 被调用方修改 -支持跨域
- 调用方修改-隐藏跨域
4.跨域问题解决方案
1.禁止浏览器检查
通过cmd命令打开一个浏览器,这里以本地的谷歌浏览器为例
C:\Users\Administrator\AppData\Local\Google\ Chrome\Application\chrome.exe --disable-web-security --user-data-dir=g:\temp3
新打开的浏览器访问同一个页面,发起同一个请求,跨域问题消失
2.jsonp
*什么是jsonp?
jsonp是后端动态创建的一个script标签
* 使用jsonp方式,需要修改后端代码吗?
需要
代码示例,这里演示采用的是laravel框架
前端:
<!doctype html>
<html>
<head>
<title></title>
<style>
*{
padding:0px;
margin:0px;
width:100%;
}
</style>
</head>
<body>
<div class="box">
<a href="#" onclick="get2()">get请求2</a>
</div>
</body>
</html>
<script src="https://code.jquery.com/jquery-3.3.1.min.js" integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8=" crossorigin="anonymous"></script>
<script>
// 使用jsonp请求处理跨域问题
function get2(){
$url="http://127.0.0.5/test2";
$.ajax({
url:$url,
dataType:"jsonp",
jsonp:"callback",
data:{"name":"zq"},
type:"get",
success:function($res){
console.log($res);
},
error:function($err){
alert(JSON.stringify($err));
}
});
}
</script>
后端代码:
/**
* 使用jsonp方式,响应请求
* 解决跨域解决方案
*/
public function test2(Request $request){
$call=$request->input("callback");
$name=$request->input("name");
Log::info("callback=".$call);
Log::info("name=".$name);
return response($call."(".json_encode(["code"=>200,"msg"=>"请求成功","data"=>$name]).")");
}
当设置dataType 为 jsonp的时候就是jsonp请求了,然后 下面的 jsonp: “callback”, 什么意思呢,jsonp方式会在客户端注册一个 js 的 callback方法,//并通过GET方式发送到服务器,见连接:
Request URL:
http://lrz.laravel.com/auth/login?callback=jQuery21307739646233126818_1491549029207&user_id=1&name=吕瑞政&_=1491549029208
jQuery21307739646233126818_1491549029207 这个方法就是客户端注册的。
然后服务器端怎么处理呢,接收 callback 的值,并返回一个JS方法的方式告知客户端,就是 return jQuery21307739646233126818_1491549029207(json_encode([1,2])); 这样的方式,客户端才能通过success: function (data) {} 获取到返回的值了
jsonp的弊端
1.需要修改服务器端代码
2.只支持get 请求方式
2.被调用方解决跨域,支持跨域请求
在laravel框架中注册一个CheckMiddleware中间件,检测框架中的指定请求,在请求头上添加响应字段,从而实现支持跨域请求:
在中间件里面添加如下代码:
实际效果
a.简单请求(get post head),请求header里面无自定义头,Content-Type为以下几种
text/plain
multipart/form-data
application/x-www-form-url-encoded
先发送请求,在判断是否为跨域请求
b.非简单请求 ,put 请求,delete请求
发送json格式的ajax请求
带自定义头的ajax请求
会先发送预检命令,预检命令通过以后才真正的发送请求
3.使用nginx解决跨域问题
server{
listen 80;
server_name zq.com
location / {
proxy_pass http://127.0.0.5:80/;
add_header Access-Control-Allow-Methods *;
add_header Access-Control-Max-Age 3600;
add_header Access-Control-Allow-Credentials true;
add_header Access-Control-Allow-Origin $http_origin;
add_header Access_Control-Allow-Headers
$http_access_control_request_headers;
if ($request_method==OPTIONS){
return 200;
}
}
}