什么是跨域
跨域是指从一个域名的网页去请求另一个域名的资源。比如从www.baidu.com 页面去请求 www.google.com 的资源。但是一般 > 情况下不能这么做,它是由浏览器的同源策略造成的,是浏览器对JavaScript施加的安全限制。跨域的严格一点的定义是:只要 > 协议,域名,端口有任何一个的不同,就被当作是跨域
https://baidu.com => https://google.com (跨域,域名不一致)
https://baidu.com => http://baidu.com (跨域,协议不一致,端口不一致,http默认端口80,https默认端口443)
http://localhost => http://127.0.0.1 (跨域,域名不一致)
http://localhost/login.html => http://localhost/api/login.php (非跨域,同源)
解决跨域的方案
通过服务端代理请求数据
当接口地址跨域时,前端收到浏览器同源限制是无法请求该接口资源的,但是可以通过后端去请求跨域接口前端再请求后端 接口拿到后端接口返回的数据完成请求,因为后端请求是不受同源策略限制的(PHP,JAVA等)
例如图灵机器人的接口就可以通过这种方案去实现http://openapi.tuling123.com/openapi/api/v2后端接口
<?php header("Content-type:text/html;charset=utf8"); /* **************************************************** 请求方式: get url: siri.php?msg=要发送的消息 return: '{intent: {actionName: "", code: 10008, intentName: ""},…}' json字符串 **************************************************** */ $text = $_GET["msg"]; function request_post($url = '', $post_data = '') { if (empty($url) || empty($post_data)) { return false; } $postUrl = $url; $curlPost = $post_data; $ch = curl_init();//初始化curl curl_setopt($ch, CURLOPT_URL,$postUrl);//抓取指定网页 curl_setopt($ch, CURLOPT_HEADER, 0);//设置header curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);//要求结果为字符串且输出到屏幕上 curl_setopt($ch, CURLOPT_POST, 1);//post提交方式 curl_setopt($ch, CURLOPT_POSTFIELDS, $curlPost); $data = curl_exec($ch);//运行curl curl_close($ch); return $data; } $url = 'http://openapi.tuling123.com/openapi/api/v2'; $post_data['userInfo']=array('apiKey'=>'yourkey','userId'=>1); $post_data['perception']=array('inputText'=>array('text'=>$text)); $post_data=json_encode($post_data); $res = request_post($url, $post_data); echo ($res) ?>JavaScript代码
ajax({ url: "data/siri.php?msg=" + msg, success: function (res) { var res = JSON.parse(res); for (let i = 0; i < res.results.length; i++) { msgV = res.results[i].values[res.results[i].resultType]; var li = document.createElement("li"); li.innerText = msgV; li.className = "msgL"; messageList.appendChild(li); } }, fail: function (fail) { console.log(fail); }, complete: function () { drawScroll() } })这种方式不需要前端去完成只需要正常请求后端接口就好
通过jsonp跨域
jsonp跨域就是利用了script标签可以跨域请求资源的能力来实现请求资源
利用js创建一个script标签,把json的url赋给script的scr属性,把这个script插入到页面里,让浏览器去跨域获取资源
回调方法要遵从服务端的约定一般是用 callback 或者 cb
callback是页面存在的回调方法,参数就是接口返回的数据
json需要服务端支持并且只能get请求
例如淘宝商品搜索的接口就是jsonp的http://suggest.taobao.com/sug?code=utf-8&q=商品关键字&callback=cb<!DOCTYPE html> <html lang="zh-CN"> <head> <title></title> <meta charset="UTF-8"> <meta name="author" content="YXGR"> <meta name="viewport" content="width=device-width, initial-scale=1"> </head> <body> <script> //cb 回调函数 //res 返回值 function cb(res) { console.log(res); } </script> <script src="http://suggest.taobao.com/sug?code=utf-8&q=970&callback=cb"></script> </body> </html>CORS 跨域资源共享(xhr2)
CORS是一个W3C标准,全称是"跨域资源共享"(Cross-origin resource sharing)
它允许浏览器向跨源服务器,发出XMLHttpRequest请求,从而克服了AJAX只能同源使用的限制
整个CORS通信过程,都是浏览器自动完成,不需要用户参与
对于开发者来说,CORS通信与同源的AJAX通信没有差别,代码完全一样
实现CORS通信的关键是服务器,只要服务器实现了CORS接口,就可以跨源通信
实现CORS只需服务端添加header(“Access-Control-Allow-Origin:*”);即可<?php header("Access-Control-Allow-Origin:*"); //下面写代码 ?>Nginx代理跨域
通过nginx的反向代理可以解决跨域问题
需要修改nginx.conf下面的配置server { listen 80; #监听80端口,可以改成其他端口 server_name localhost; # 当前服务的域名 #charset koi8-r; #access_log logs/host.access.log main; location / { proxy_pass http://localhost:81; proxy_redirect default; } location /apis { #添加访问目录为/apis的代理配置 rewrite ^/apis/(.*)$ /$1 break; proxy_pass http://localhost:82; }
跨域问题是前后端通信中经常遇到的问题可以根据问题和实际情况的不同来选择不同的解决方案
这里写出的只是一部分方案