只有ajax会跨域吗_ajax跨域请求原理及解决方案分析

##1. 什么是跨域(Cross-site)?

想了解跨域,必须先了解一下“同源策略(same origin policy)”。

1.1 同源策略

它限制了某个域下的文档或者js与另一个域中的资源交互的方式,它提供了一种安全机制,这种安全机制可以避免来自恶意网站的攻击。 同源策略要求浏览器允许来自某个网页上的js请求来自另一个网页的数据,当且仅当两个页面来自相同的域。

1.2 什么是域(origin)?

域是由三部分组合而成:URI Schema(协议类型),host name(域名),port number(端口号)

举个例子:

1) http://www.domain.com 这个页面,URI Schema是http,host name是www.domain.com,port number是默认的80

2) https://www.xxx.com:8080/xxx/yyy URI Schema是https,hostname是www.xxx.com,port number是8080

由于1)和2)中的三部分都不相同,所以它们就是不同的域。 下面的图更好的解释了什么是同域:

82c04776acca0c7542da90f7ca91e7f3.png

PS:IE浏览器里可能不太一样,它不会把端口号作为判断依据。

1.3 为什么要有同源策略?

提出同源策略的目的是出于安全性考虑,它能够阻止来自恶意网站的脚本通过其他网站的DOM获取其他网站的信息。可以避免CSRF和XSS攻击。

1.4 同源策略是限制谁的?

1) 很多人可能搞不清楚这个问题,同源策略限制的是浏览器或者其他提供类似浏览器服务的软件,而且这仅仅是个规范,所以浏览器是否遵守这个规范也不一定,所以就会有上面的IE浏览器判断是否同源的时候并没有考虑端口号的问题。 2) 同源策略限制的是js,而图片,css这些是不存在同源策略限制的。

1.5 什么是跨域?

在某个网站的页面上通过js请求另外一个网站的数据,如果两个网站不满足同源策略,那么就存在跨域问题。

2. 为什么会有跨域问题?

由于在实际环境中,经常需要通过js获取一些数据,特别是ajax的流行,通过ajax加载某个网站的数据的场景就会经常遇到,而一旦有这样的需求,就可能会出现跨域的问题。

3. 如何判断我是否遇到了跨域问题?

一般来讲,如果你的请求被同源策略限制,浏览器的开发工具都会给出错误提示,在chrome_6494_1.html' target='_blank'>Chrome浏览器的console中,可能会有类似下面的提示:

32f343e782c57c1fcfd1dfcbb94056dc.png

4.如何解决跨域问题?

一般的思路是:通过一些妥协调整,绕过同源策略的限制。下面是我最近了解的一些方法。

为方便讲解,这里先举一个例子:

客户端采用H5开发,所有的数据都通过ajax请求从服务端获取。

客户端的页面都存放在静态文件服务器中,域名是http://static.demo.com

服务端提供接口供客户端调用,接口的参数和返回值都是JSON格式,服务端的域名是:http://server.demo.com。

如果不考虑跨域的问题,客户端与服务端的交互方式如下:

1.客户端post请求服务端,参数:{"key":"value"}

2.服务端返回结果:{"code":1,"data":"success"}

4.1 Jsonp方式

原理: 通过在页面中新增一个

实现举例:

1)服务端修改返回的数据类型为js,同时在请求参数中增加一个callback字段,这个字段用于客户端传递要执行的js方法名称。 2)客户端传递的参数中增加callback,同时将普通的ajax方法改成在页面中新增一个

1.通过js在页面中append如下标签

增加该标签之后,浏览器就会立即去请求这个url,由于

2.服务端收到callback参数之后,将它拼接在返回的数据中,返回的数据如下:

parseResponse({"Name": "Foo", "Id": 1234, "Rank": 7});

3.这样返回之后,就调用页面上的parseResponse js方法,就达到了数据处理的目的。

4.最后将刚刚新增加到页面中的

4.2 设置document.domain属性

如果两个页面或者frame可以将document.domain属性设置成相同的值,那么也可以绕过同源策略限制。 假设两个页面分别是static.demo.com和server.demo.com,两个页面加载之后都通过js将document.domain设置成demo.com,这样接下来的ajax请求就可以绕过同源策略限制了。

但是:如果两个页面存在端口,比如static.demo.com:8080 和 server.demo.com:8090,由于document.domain只能设置域名,所以就不起作用。

举例:

上面的例子,由于服务端返回的是json,而不是一个页面,所以没法将自己的域名设置成demo.com,但是可以通过另外一种方式,即在服务端增加一个静态页面,页面中放如下js代码:

document.domain=demo.com

或者如下代码:

try{document.domain = window.location.hostname.split('.').reverse().slice(0,2).reverse().join('.');}catch(e){}

然后客户端页面加载的时候先去调用一下这个静态页面就好了。

4.3 CORS(Cross-Origin Resource Sharing)

原理MDN上讲的更清楚一些,点击这里。 其实简单来说就是服务端在响应头中添加一个Access-Control-Allow-Origin头部,头部的值为客户端的域名,比如:http://static.demo.com,这样就可以了。

但是需要注意的是:CROS分为两种,一种是简单请求,一种是复杂请求,简单请求按照上面的方式是可以的,如果是复杂请求,浏览器会进行两步,先发一个options请求,这个请求称之为“预请求”,预请求实际上是个OPTIONS请求,类似于一个探测作用,如果服务端返回的头部通过了预请求的内容,则浏览器才会发起第二个真实请求。这个后续我会有详细文章介绍。

4.4 客户端请求通过Nginx转发

原理:客户端的所有请求都直接发到客户端所在域名下,但是在客户端服务器增加一台nginx服务器,作为代理,如果是后端的url,直接代理转发到服务端,这样就不存在前端的跨域问题了。

举例:

server {

listen       80;

server_name  static.demo.com;    #可配置多个主机头

charset utf-8,gbk,gb2312,gb18030; #可以实现多种编码识别

location / {

root   /home/wy/www/static.demo.com/ROOT;  #网站文件路径

autoindex on;

autoindex_exact_size off;

autoindex_localtime on;

index  default.html;

}

#所有/server/开头的请求都会走这里

location /server/ {

proxy_pass http://server.demo.com:8080;  ##转发到server

proxy_set_header    Host             $host;

proxy_set_header    X-Real-IP        $remote_addr;

proxy_set_header    X-Forwarded-For  $proxy_add_x_forwarded_for;

}

}

4.5 其他方式

1)WebSocket 2)Cross-document messaging

标签: ajax

顶一下

(0)

0%

踩一下

(0)

0%

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值