在浏览器请求中,出现跨域访问资源的问题,我们肯定会遇到。如果跨域请求被阻止,有可能导致css、js 、ajax请求、font字体等资源出现无法正常访问的问题。
跨域
跨域是指一个域下的文档或者脚本试图去请求另一个域下的资源。
广义的跨域
资源跳转:a链接跳转、重定向、表单提交;资源嵌入:<link>、<script>、<frame>等DOM操作标签;js 发起的 ajax 请求、dom 和 js 对象的跨域操作等;
狭义的跨域
浏览器同源策略限制
同源策略
同源策略/SOP(Same origin policy)是一种约定,由Netscape公司1995年引入浏览器,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,浏览器很容易受到XSS、CSFR等攻击。所谓同源是指"协议+域名+端口"三者相同,即便两个不同的域名指向同一个ip地址,也非同源。
同源策略限制:
Cookie、LocalStorage 和 IndexDB 无法读取DOM 和 JS 对象无法获取AJAX 请求不能发送
注意:
如果是协议和端口造成的跨域问题“前台”是无能为力的;在跨域问题上,域仅仅是通过“URL的首部”来识别而不会去尝试判断相同的ip地址对应着两个域或两个域是否在同一个ip上。
前端跨域解决方案
一、jsonp跨域
通常为了减轻web服务器的负载,我们把js、css,img等静态资源分离到另一台独立域名的服务器上,在html页面中再通过相应的标签从不同域名下加载静态资源,而被浏览器允许,基于此原理,我们可以通过动态创建script,再请求一个带参网址实现跨域通信。简单点来说就是:动态创建script,再请求一个带参网址实现跨域通信(script 标签的 src 属性不受同源策略的限制 );缺点是只能实现 get 一种请求,容易遭受 xss 攻击。
二、CORS(跨域资源共享)
普通跨域请求:只服务端设置Access-Control-Allow-Origin即可,前端无须设置,若要带cookie请求:前后端都需要设置。 需注意的是:由于同源策略的限制,所读取的cookie为跨域请求接口所在域的cookie,而非当前页。 目前,所有浏览器都支持该功能(IE8+:IE8/9需要使用XDomainRequest对象来支持CORS)),CORS也已经成为主流的跨域解决方案。
# 配置 cors 跨域
header("Access-Control-Allow-Origin:*");
header("Access-Control-Request-Methods:GET, POST, PUT, DELETE, OPTIONS");
header('Access-Control-Allow-Headers:x-requested-with,content-type,test-token,test-sessid');
三、nginx配置代理(proxy)
配置代理分为正向代理和反向代理两种形式。
正向代理
有一个客户端需要向一个非同源的服务器B发送请求,我们搭建一个和客户端同源的服务器A,当客户端发送请求的时候,由服务器A来接受,再由服务器A向服务器B发送请求,因为 同源策略是由浏览器给的,服务器之间没有。服务器B接受到请求以后,会处理请求,并把响应返回给服务器A,再由服务器A把响应给到客户端就可以了。我们就可以用这个方式来进行跨域请求了。
反向代理
反向代理一般是用来做负载均衡的当我请求一个服务器的时候,其实请求的是服务器端设置的代理服务器,由代理服务器把若干大量的请求分发给不同的服务器进行处理,再由服务器把响应给到代理服务器,代理服务器返回给客户端。
服务器配置文件
ngnix 后台配置
server
{
# 监听的端口号
listen
80;
# 服务器名称
;
server_name localhost
;
# 根目录
;
root
"D:/phpstudy_pro/WWW";
# 配置的代理
;(在这里配置
)
location
= /baidu
{
proxy_pass https
://www
.baidu
.com
/sugrec
;
}
location
= /pxx
{
proxy_pass https
://apiv2
.pinduoduo
.com
/api
/gindex
/subject
/limited
/goods
;
}
# location
=> 地址栏信息
;
# http
://localhost
/php
/day26
/xxx
.html
;
# http
:// : 给浏览器看的
, 让浏览器知道用什么样的方式去进行请求的发送,响应的接受
;
# localhost
: 给浏览器看的
,让浏览器可以向对应的ip地址(目标
)发起请求
;
#
/php
/day26
/xxx
.html 服务器查询语句
;
# 在nginx之中由 location 来进行捕获并处理
;
# http
://localhost
: 默认就是传递一个
/ 给服务器
;
# file
:/
# 重要
: 如果更改了配置文件,那么必须重启服务器
;
location
/ {
index index
.php index
.html
;
error_page
400 /error
/400.html
;
error_page
403 /error
/403.html
;
error_page
404 /error
/404.html
;
error_page
500 /error
/500.html
;
error_page
501 /error
/501.html
;
error_page
502 /error
/502.html
;
error_page
503 /error
/503.html
;
error_page
504 /error
/504.html
;
error_page
505 /error
/505.html
;
error_page
506 /error
/506.html
;
error_page
507 /error
/507.html
;
error_page
509 /error
/509.html
;
error_page
510 /error
/510.html
;
autoindex on
;
}
#
.php后缀的内容需要用php解析
;
#
/\
.php(.*)$
/ 正则
location
~ \
.php(.*)$
{
fastcgi_pass
127.0.0.1:9000;
fastcgi_index index
.php
;
fastcgi_split_path_info
^((?U).+\
.php
)(/?.+)$
;
fastcgi_param
SCRIPT_FILENAME $document_root$fastcgi_script_name
;
fastcgi_param
PATH_INFO $fastcgi_path_info
;
fastcgi_param
PATH_TRANSLATED $document_root$fastcgi_path_info
;
include fastcgi_params
;
}
}
前端 js 配置
<script
>
var options
= {
url
: "http://localhost/baidu",
success
: function(res
){
console
.log(res
);
},
dataType
: "json",
data
: {
wd
: "你好",
prod
: "pc",
sugsid
: "1423,31169,21125,30839,31187,30823,22159",
}
}
ajax(options
)
</script
>
四、Nodejs中间件代理
node中间件实现跨域代理,原理大致与nginx相同,都是通过启一个代理服务器,实现数据的转发 使用 node + express + http-proxy-middleware 搭建一个proxy服务器。
前端代码示例
var xhr
= new XMLHttpRequest();
xhr
.withCredentials
= true;
xhr
.open( 'get', 'http://www.domain1.com:3000/login?user=admin', true);
xhr
.send();
中间件服务器代码示例
var express
= require( 'express' );
var proxy
= require( 'http-proxy-middleware');
var app
= express();
app
.use("/" , proxy({
target
: 'http://www.domain2.com:808e',
changeorigin
: true,
onProxyRes
: function(proxyRes
, req
, res
) {
res
.header( 'Access-Control-Allow-Origin', 'http://www.domain1.com');
res
.header( 'Access-Control-Allow-Credentials ', 'true' );
},
cookieDomainRewrite
: 'www.domain1.com'
}));
app
.listen( 3000);
console
.log('Proxy server is listen at port 3000...');
nodejs 后台代码示例同 三、nginx配置代理(proxy)
五、WebSocket协议
web sockets是一种浏览器的API,它的目标是在一个单独的持久连接上提供全双工、双向通信。(同源策略对web sockets不适用)
web sockets原理:在JS创建了web socket之后,会有一个HTTP请求发送到浏览器以发起连接。取得服务器响应后,建立的连接会使用HTTP升级从HTTP协议交换为web sockt协议。
只有在支持web socket协议的服务器上才能正常工作。
var socket
= new WebSockt('ws://www.baidu.com');
socket
.send('hello WebSockt');
socket
.onmessage = function(event
){
var data
= event
.data
;
}