Fork me on GitHub

Ajax跨域完全讲解

什么是跨域?为什么会发生跨域?

      当请求的地址与来源地址的协议\域名\端口中的任一值不相同时, 均视为是一个跨域的请求,如果请求的TYPE 是XMLHttpRequest(xhr) 则根据浏览器的同源策略,浏览器请求发送出去会收到正常返回结果,但是浏览器不会解析,因为浏览器禁止了跨域请求解析。
      同时w3c 为浏览器制定了可以跨域通信规范Cross-Origin Resource Sharing(CORS)通过使用 XMLHttpRequest 对象, CORS可以让开发者方便的进行跨域通信,通过添加一些特殊的请求\响应头, 就像在使用同域通信一样.

解决跨域的方法

1.浏览器中关闭跨域检查,就可以解析跨域问题。(放弃)

缺点:

  • 需要每个客户端都关闭跨域,不现实
  • 浏览器默认启用,足以说明安全性,启用会导致一些安全性问题。

缺点很明显,所以就不做过多分析,没人用这种方法

展示:

cmd进入chrome.exe的目录键入以下命令
1
C:\Users\Lu\AppData\Local\Google\Chrome>chrome --disable-web-security  --user-data-dir

2.通过JSONP实现跨域请求

如何解决跨域?

  1.JSONP是什么?
      HTML 的<script> 元素是一个例外(支持跨域)。利用 <script> 元素的这个开放策略,网页可以得到从其他来源动态产生的 JSON 资料,而这种使用模式就是所谓的 JSONP。用 JSONP 抓到的资料并不是 JSON,而是任意的JavaScript,用 JavaScript 直译器执行而不是用 JSON 解析器解析。
  2.JSONP的原理?
      发送一个jsonp的请求,实际是发送一个请求,并且添加一个collback的参数方法给后台,后台将数据作为 对象内容,将jsonp传过来的collback值作为方法名称返回前段为一个 script 方法,方法名就是collback的值,方法体就是我们请求返回的内容,因为script 没有跨域问题,这里就是script的解析了,解析出我们的数据。
      简单说:前段发送地址和script方法名->后台获取方法名,查询数据 包装为script function返回给前短,动态插入使用后删除,浏览器script支持跨域方法调用。
  3.JSONP修改方式? 需要修改后端代码

  • 前段请求发送agax请求 添加 dataType: “jsonp” //默认请求自动添加callback参数
  • 后台添加jsonp支持 添加 JsonpAdvice extends AbstractJsonpResponseBodyAdvice
1
2
3
4
5
6
@ControllerAdvice
class JsonpAdvice extends AbstractJsonpResponseBodyAdvice{
public JsonAdvice(){
super("callback"); //添加前段传来的callback【名字可变,前后保持一致即可】
}
}
  • 发送的请求 TYPE 是 script 格式,context-type 是 application/javascript

  4.弊端

  • jsonp 需要改动服务端,当我们是调用方,改不了 被调用方的服务端。
  • jsonp只支持GET请求,不能满足日常开发
  • 发送的不是XHR请求,不能使用XHR的新特性,不方便

解决XHR的跨域请求(推荐使用)

解决XHR的跨域 的原理?

 

浏览器对XHR跨域拦截是先请求还是先判断?

简单请求 【先请求,后判断】

      方法为:
             GET
             HEAD
             POST
       请求header里面
       无自定义头
       Content-Type为以下几种:
             text/plain
             multipart/form-data
             application/x-www-form-urlencoded

非简单请求 【先判断后请求】

       工作中常见的有:
             put、delete 方法的ajax请求
             发送json格式的ajax请求
             带自定义头的ajax请求

非简单请求 会现发送一个 options 的请求,主要是确定服务端是否支持跨域,如果支持,则发送真正请求,如果不支持,将不会发送真正请求。

如何判断?

浏览器查看返回的response中是否有 Origin 标示,如果没有则表示不支持跨域,有则是 W3C 的CORS规范实现跨域。

被调用方解决跨域

      服务端解决 Filter设置 origin参数
编写filter添加两个参数,代码如下:(不满足带coocik的请求)

![](http://githubimg.lushunde.com/2018-03-20_231854.jpg)

查看请求返回response header

![](http://githubimg.lushunde.com/2018-03-20_231825.jpg)

nginx 解决

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
server{
listen 80;
server_name b.com;

location / {
proxy_pass http://localhost:8080/;

add_header Access-Control-Allow-Methods *;
add_header Access-Control-Max-Age 3600;
add_header Access-Control-Allow-Credentials true;

add_header Access-Control-Allow-Origin $http_origin;
add_header Access-Control-Allow-Headers $http_access_control_request_headers;

if($request_method = OPTIONS){
return 200;
}

}
}

spring配置

@CrossOrigin 注解可以直接 解决 跨域

  • 可以加在在方法上
  • 也可以加在类上
1
2
3
4
5
6
7
8
9
@RestController
@RequestMapping("user")
@CrossOrigin
public class UserController{
@GetMapping("getUser")
public ResultBean getUser(){
return new resultBean;
}
}

调用方解决

nginx 解决

1
2
3
4
5
6
7
8
9
10
11
12
server{
listen 80;
server_name a.com;

location / {
proxy_pass http://localhost:8081/;
}

location /ajaxserver{
proxy_pass http://localhost:8080/test/;
}
}

相关视频:慕课网 http://www.imooc.com/learn/947

------本文结束 感谢阅读------
鲁顺德 wechat
欢迎您扫一扫上面的微信公众号,订阅我的分享资源!
坚持原创技术分享,您的支持将鼓励我继续创作!