跨域,指的是从一个域名去请求另一个域名的资源。即跨域名请求!跨域时,浏览器不能执行其余域名网站的脚本,是由浏览器的同源策略形成的,是浏览器施加的安全限制。php
同源策略是一种约定,它是浏览器最核心也最基本的安全功能,若是缺乏了同源策略,浏览器很容易受到XSS、CSFR等攻击。所谓同源是指"协议+域名+端口"三者相同,即使两个不一样的域名指向同一个ip地址,也非同源。html
同源策略限制内容有:前端
可是有三个标签是容许跨域加载资源:mysql
当协议、子域名、主域名、端口号中任意一个不相同时,都算做不一样域。不一样域之间相互请求资源,就算做“跨域”。webpack
特别说明两点: web
第一:若是是协议和端口形成的跨域问题,那么“前台”是无能为力的。sql
第二:在跨域问题上,仅仅是经过“URL的首部”来识别,而不会根据域名对应的IP地址是否相同来判断。“URL的首部”能够理解为“协议, 域名和端口必须匹配”。json
这里你或许有个疑问:请求跨域了,那么请求到底发出去没有?后端
跨域并非请求发不出去,请求能发出去,服务端能收到请求并正常返回结果,只是结果被浏览器拦截了。
你可能会疑问明明经过表单的方式能够发起跨域请求,为何 Ajax 就不会?由于归根结底,跨域是为了阻止用户读取到另外一个域名下的内容,Ajax 能够获取响应,浏览器认为这不安全,因此拦截了响应。
可是表单并不会获取新的内容,因此能够发起跨域请求。同时也说明了跨域并不能彻底阻止 CSRF,由于请求毕竟是发出去了。
PHP解决跨域问题的方法
跨域的严格一点来讲就是只要协议,域名,端口有任何一个的不一样,就被看成是跨域。
好比,在实际项目中因为先后端分离当前端须要经过接口向后台发起请求,此时就会出现跨域问题,那么,这类问题须要如何解决呢?
其实php解决跨域问题很简单,只需加上下面的代码就能够了:
header("Access-Control-Allow-Origin:*");
加上这行代码表示容许全部的域名访问,不过为了安全起见,在实际项目中每每会限定只容许固定的几个域名和方法发起的请求。
一、容许单个域名访问
header('Access-Control-Allow-Origin:http://www.startphp.cn'); header('Access-Control-Allow-Methods:POST'); //表示只容许POST请求 header('Access-Control-Allow-Headers:x-requested-with, content-type'); //请求头的限制
二、不限制域名
header('Access-Control-Allow-Origin:*'); header('Access-Control-Allow-Methods:POST');//表示只容许POST请求 header('Access-Control-Allow-Headers:x-requested-with, content-type');
三、容许多个域名访问
在实际项目中最好指定能跨域访问的域名,增长安全性。能够写在一个公共类里面,封装一个方法调用。
// 设置能访问的域名 static public $originarr = [ 'https://test1.com', 'https://test2.com', ]; /** * 公共方法调用 */ static public function setheader() { // 获取当前跨域域名 $origin = isset($_SERVER['HTTP_ORIGIN']) ? $_SERVER['HTTP_ORIGIN'] : ''; if (in_array($origin, self::$originarr)) { // 容许 $originarr 数组内的 域名跨域访问 header('Access-Control-Allow-Origin:' . $origin); // 响应类型 header('Access-Control-Allow-Methods:POST,GET'); // 带 cookie 的跨域访问 header('Access-Control-Allow-Credentials: true'); // 响应头设置 header('Access-Control-Allow-Headers:x-requested-with,Content-Type,X-CSRF-Token'); } }
在php上如何实现
<?php // 制定容许其余域名访问 header("Access-Control-Allow-Origin:*"); // 响应类型 header('Access-Control-Allow-Methods:POST'); // 响应头设置 header('Access-Control-Allow-Headers:x-requested-with, content-type'); //$callback = isset($_REQUEST['callback']) ? trim($_REQUEST['callback']) : ''; //jsonp回调参数,必需 function getKey($key,$default=""){ return trim(isset($_REQUEST[$key])?$_REQUEST[$key]:$default); } $id = getKey("id"); $conn = mysqli_connect("localhost","root","","test") or die("链接失败"); $conn->query("set names utf8"); $sql = "select * from data where ".$id." is not null"; $result = $conn->query($sql); $arr = []; while($row=$result->fetch_assoc()){ array_push($arr,json_encode($row)); } $json = json_encode($arr); //json 数据 print_r($json);
4 代理,这种常常用
好比http://www.startphp.cn/index....://www.mano100.cn/server.php,咱们能够这样作,写一个接口http://www.startphp.cn/server...,由这个接口在后端去调用http://www.mano100.cn/server....,而后再返回给index.html,这就是一个代理的模式。至关于绕过了浏览器端,天然就不存在跨域问题。
5 Nginx反向代理
使用nginx反向代理实现跨域,是最简单的跨域方式。只须要修改nginx的配置便可解决跨域问题,支持全部浏览器,支持session,不须要修改任何代码,而且不会影响服务器性能。
实现思路:经过nginx配置一个代理服务器(域名与domain1相同,端口不一样)作跳板机,反向代理访问domain2接口,而且能够顺便修改cookie中domain信息,方便当前域cookie写入,实现跨域登陆。
修改配置文件nginx.conf,以下:
// proxy服务器 server { listen 81; server_name www.domain1.com; location / { proxy_pass http://www.domain2.com:8080; #反向代理 proxy_cookie_domain www.domain2.com www.domain1.com; #修改cookie里域名 index index.html index.htm; # 当用webpack-dev-server等中间件代理接口访问nignx时,此时无浏览器参与,故没有同源限制,下面的跨域配置可不启用 add_header Access-Control-Allow-Origin http://www.domain1.com; #当前端只跨域不带cookie时,可为* add_header Access-Control-Allow-Credentials true; } }
配置修改好后,再重启nginx。
index.html文件访问代理服务器
// index.html var xhr = new XMLHttpRequest(); // 前端开关:浏览器是否读写cookie xhr.withCredentials = true; // 访问nginx中的代理服务器 xhr.open('get', 'http://www.domain1.com:81/?user=admin', true); xhr.send();
server.js
// server.js var http = require('http'); var server = http.createServer(); var qs = require('querystring'); server.on('request', function(req, res) { var params = qs.parse(req.url.substring(2)); // 向前台写cookie res.writeHead(200, { 'Set-Cookie': 'l=a123456;Path=/;Domain=www.domain2.com;HttpOnly' // HttpOnly:脚本没法读取 }); res.write(JSON.stringify(params)); res.end(); }); server.listen('8080'); console.log('Server is running at port 8080...');