如何实现跨域

引言:

当浏览器执行 JS 脚本的时候,会检测脚本要访问的协议、域名、端口号是不是和当前网址一致,如
果不一致就是跨域。跨域是不允许的,这种限制叫做浏览器的同源策略,简单点的说法就是浏览器
不允许一个源中加载脚本与其他源中的资源进行交互。那么如何实现跨域呢?

JSONP、CORS方式、代理方式

1 JSONP 方式:
script、img、iframe、link、video、audio 等带有 src 属性的标签可以跨域请求和执行资源,JSONP 利用这一点“漏洞”实现跨域。

<script>
var scriptTag = document.createElement('script');
scriptTag.type = "text/javascript";
scriptTag.src = "http://10.10.0.101:8899/jsonp?callback=f";
document.head.appendChild(scriptTag);
</script>

再看下 jQuery 的写法。

$.ajax({
	// 请求域名
	url:'http://10.10.0.101:8899/login',
	// 请求方式
	type:'GET',
	// 数据类型选择 jsonp
	dataType:'jsonp',
	// 回调方法名
	jsonpCallback:'callback',
});
// 回调方法
function callback(response) {
	console.log(response);
}

JSONP 实现跨域很简单但是只支持 GET 请求方式。而且在服务器端接受到 JSONP 请求后需要设置
请求头,添加 Access-Control-Allow-Origin 属性,属性值为 * ,表示允许所有域名访问,这样浏
览器才会正常解析,否则会报 406 错误。

response.setHeader("Access-Control-Allow-Origin", "*");

2 CORS 方式:

CORS(Cross-Origin Resource Sharing)即跨域资源共享,需要浏览器和服务器同时支持,这种
请求方式分为简单请求和非简单请求。

当浏览器发出的 XMLHttpRequest 请求的请求方式是 POST 或者 GET,请求头中只包含 Accept、
Accept-Language、Content-Language、Last-Event-ID、Content-Type(application/x-www-
form-urlencoded、multipart/form-data、text/plain)时那么这个请求就是一个简单请求。

对于简单的请求,浏览器会在请求头中添加 Origin 属性,标明本次请求来自哪个源(协议 + 域名 +
端口)

GET
// 标明本次请求来自哪个源(协议+域名+端口)
Origin: http://127.0.0.1:8080
// IP
Host: 127.0.0.1:8080
// 长连接
Connection: keep-alive
Content-Type: text/plain

如果 Origin 标明的域名在服务器许可范围内,那么服务器就会给出响应:

// 请求方式
type:'GET',
// 数据类型选择 jsonp
dataType:'jsonp',
// 回调方法名
jsonpCallback:'callback',
});
// 回调方法
function callback(response) {
	console.log(response);
}
response.setHeader("Access-Control-Allow-Origin", "*");

// 该值上文提到过,表示允许浏览器指定的域名访问,要么为浏览器传入的 origin,要么为 * 表示所有域名都可以访问

Access-Control-Allow-Origin: http://127.0.0.1:8080
// 表示服务器是否同意浏览器发送 cookie
Access-Control-Allow-Credentials: true
// 指定 XMLHttpRequest#getResponseHeader() 方法可以获取到的字段
Access-Control-Expose-Headers: xxx
Content-Type: text/html; charset=utf-8

Access-Control-Allow-Credentials: true 表示服务器同意浏览器发送 cookie,另外浏览器也需要
设置支持发送 cookie,否则就算服务器支持浏览器也不会发送。

var xhr = new XMLHttpRequest();
// 设置发送的请求是否带 cookie
xhr.withCredentials = true;
xhr.open('post', 'http://10.10.0.101:8899/login', true);
xhr.setRequestHeader('Content-Type', 'text/plain');

另外一种是非简单请求,请求方式是 PUT 或 DELETE,或者请求头中添加了 Content-
Type:application/json 属性和属性值的请求。

这种请求在浏览器正式发出 XMLHttpRequest 请求前会先发送一个预检 HTTP 请求,询问服务器当
前网页的域名是否在服务器的许可名单之中,只有得到服务器的肯定后才会正式发出通信请求。

预检请求的头信息:

// 预检请求的请求方式是 OPTIONS
OPTIONS
// 标明本次请求来自哪个源(协议+域名+端口)
Origin: http://127.0.0.1:8080
// 标明接下来的 CORS 请求要使用的请求方式
Access-Control-Request-Method: PUT
// 标明接下来的 CORS 请求要附加发送的头信息属性
Access-Control-Request-Headers: X-Custom-Header
// IP
Host: 127.0.0.1:8080
// 长连接
Connection: keep-alive

如果服务器回应预检请求的响应头中没有任何 CORS 相关的头信息的话表示不支持跨域,如果允许
跨域就会做出响应,响应头信息如下:

HTTP/1.1 200 OK
// 该值上文提到过,表示允许浏览器指定的域名访问,要么为浏览器传入的 origin,要么为 * 表示所有域名都可以访问
Access-Control-Allow-Origin:http://127.0.0.1:8080
// 服务器支持的所有跨域请求方式,为了防止浏览器发起多次预检请求把所有的请求方式返回给浏览器
Access-Control-Allow-Methods: GET, POST, PUT
// 服务器支持预检请求头信息中的 Access-Control-Request-Headers 属性值
Access-Control-Allow-Headers: X-Custom-Header
// 服务器同意浏览器发送 cookie
Access-Control-Allow-Credentials: true
// 指定预检请求的有效期是 20 天,期间不必再次发送另一个预检请求
Access-Control-Max-Age:1728000
Content-Type: text/html; charset=utf-8
Keep-Alive: timeout=2, max=100
// 长连接
Connection: Keep-Alive
Content-Type: text/plain

接着浏览器会像简单请求一样,发送一个 CORS 请求,请求头中一定包含 Origin 属性,服务器的响
应头中也一定得包含 Access-Control-Allow-Origin 属性。

3 代理方式:
跨域限制是浏览器的同源策略导致的,使用 nginx 当做服务器访问别的服务的 HTTP 接口是不需要
执行 JS 脚步不存在同源策略限制的,所以可以利用 Nginx 创建一个代理服务器,这个代理服务器的
域名跟浏览器要访问的域名一致,然后通过这个代理服务器修改 cookie 中的域名为要访问的 HTTP
接口的域名,通过反向代理实现跨域。
Nginx 的配置信息:

 server {
        # 代理服务器的端口
        listen 88;
        # 代理服务器的域名
        server_name http://127.0.0.1;
        location / {
            # 反向代理服务器的域名+端口
            proxy_pass http://127.0.0.2:89;
            # 修改cookie里域名
            proxy_cookie_domain http://127.0.0.2 http://127.0.0.1;
            index index.html index.htm;
            # 设置当前代理服务器允许浏览器跨域
            add_header Access-Control-Allow-Origin http://127.0.0.1;
            # 设置当前代理服务器允许浏览器发送 cookie
            add_header Access-Control-Allow-Credentials true;
            }
        }

前端代码:

var xhr = new XMLHttpRequest();
// 设置浏览器允许发送 cookie
xhr.withCredentials = true;
// 访问 nginx 代理服务器
xhr.open('get', 'http://127.0.0.1:88', true);
xhr.send();
  • 39
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序员JavaWind

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值