AJAX与跨域访问

ASynchronous JavaScript And XML

  • 异步和同步:在客户端和服务器端相互通信的基础上
    • 同步:客户端必须等待服务器端的响应。在等待的期间客户端不能做其他操作。
    • 异步:客户端不需要等待服务器端的响应。在服务器处理请求的过程中,客户端可以进行其他的操作。
  • Ajax 是一种在无需重新加载整个网页的情况下,能够更新部分网页的技术。
    • 可以在不重新加载整个网页的情况下,对网页的某部分进行更新。
  • 传统的网页(不使用 Ajax)如果需要更新内容,必须重载整个网页页面。
  • 可以提升用户的体验

注意事项

服务器响应的数据,在客户端要想当做json数据格式使用, 需要在服务端设置MIME类型 content-type=application/json;charset=utf-8

js原生方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
//1.创建核心对象
var xmlhttp;
if (window.XMLHttpRequest)
{// code for IE7+, Firefox, Chrome, Opera, Safari
xmlhttp=new XMLHttpRequest();
}
else
{// code for IE6, IE5
xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
}

//2. 建立连接
/*
open方法参数:
1. 请求方式:GET、POST
* get方式,请求参数在URL后边拼接。send方法为空参
* post方式,请求参数在send方法中定义
2. 请求的URL:
3. 同步或异步请求:true(异步)或 false(同步)
*/
xmlhttp.open("GET","ajaxServlet?username=tom",true);

//3.发送请求
xmlhttp.send();

//4.接受并处理来自服务器的响应结果
//获取方式 :xmlhttp.responseText

//当xmlhttp对象的就绪状态改变时,触发事件onreadystatechange。
xmlhttp.onreadystatechange=function()
{
//判断readyState就绪状态是否为4,判断status响应状态码是否为200
if (xmlhttp.readyState==4 && xmlhttp.status==200)
{
//获取服务器的响应结果
var responseText = xmlhttp.responseText;
alert(responseText);
}
}

JQeury方式

  1. $.ajax()

    • 语法:$.ajax({键值对});

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      //使用$.ajax()发送异步请求
      $.ajax({
      url:"ajaxServlet1111" , // 请求路径
      type:"POST" , //请求方式
      //data: "username=jack&age=23",//请求参数
      data:{"username":"jack","age":23},
      success:function (data) {
      alert(data);
      },//响应成功后的回调函数
      error:function () {
      alert("出错啦...")
      },//表示如果请求响应出现错误,会执行的回调函数

      dataType:"text"//设置接受到的响应数据的格式
      });
  2. $.get():发送get请求

    • 语法:$.get(url, [data], [callback], [type])
      • url:请求路径
      • data:请求参数
      • callback:回调函数
  • type:响应结果的类型
  1. $.post():发送post请求
    • 语法:$.post(url, [data], [callback], [type])

fetch发送异步请求

常用配置选项

  • method(String)
  • body(String)
  • headers(Object)

示例

1
2
3
fetch("http://localhost/products", {method: "GET"})
.then(data => data.text()) // data.text()返回的是一个Promise对象
.then(data => console.log(data)); // 这时拿到的data才是响应数据

axios发送异步请求

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 请求拦截器, 在请求发出前设置一些信息
axios.interceptors.request.use(config => {
console.log(config);
config.headers.mytoken = "hello";
},error => console.log(error))

// 响应拦截器, 在获取数据前做一些处理
axios.interceptors.response.use(res => console.log(res),
error => console.log(error))

// 发送get请求
axios.get("http://localhost/products")
.then(resp => console.log(resp.data))
.catch(error => console.log(error));

同源政策

如果两个页面拥有相同的协议(http/https)、域名端口,那么这两个页面就属于统一个源。

同源政策的目的就是为了保证用户信息的安全。

同源限制

  • A网站在客户端设置的Cookie,B网站不能访问
  • 向非同源的地址发送ajax请求,浏览器会拒绝接收(但能发送请求)。

Jsonp

json with padding, 不属于ajax请求,但可以模拟ajax请求,解决同源限制问题。

实现步骤

  1. 将不同源的请求地址写道script标签的src属性中,并设置请求参数callbak
  2. 服务器端响应一个函数调用的字符串,让客户端调用。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<body>

<button onclick="findAll()">查看所有商品</button>

</body>
<script>
// 封装jsonp操作
function jsonp(options) {
// 创建script标签
let script = document.createElement("script");

// 将临时的success函数挂载到window对象上
let functionName = "jsonp" + new Date().getMilliseconds();
window[functionName] = options.success;

// 将success函数名,通过参数传递给服务器;
// 服务器收到后,返回一个调用该函数的字符串代码给客户端执行
script.src = `${options.url}?callback=${functionName}`;

document.body.appendChild(script); // 向dom中添加script标签
document.body.removeChild(script); // 在dom中删除script标签
}

function findAll() {
jsonp({
url: "http://localhost/product/findAll",
success: function (data) {
alert(JSON.stringify(data));
}
});
}
</script>

CORS跨域资源共享

优质博文: https://www.ruanyifeng.com/blog/2016/04/cors.html

Cross-origin resource sharing, 允许浏览器向跨域服务器发送Ajax请求。

CORS需要浏览器和服务器同时支持。目前,所有浏览器都支持该功能 。整个CORS通信过程,都是浏览器自动完成,不需要用户参与。 因此,实现CORS通信的关键是服务器。

简单请求

  • 请求方法是一下三者之一:HEAD、GET、POST
  • HTTP头不能超过一下几种字段:
    • Accept
    • Accept-Language
    • Content-Language
    • Last-Event-ID
    • Content-Type:只限于三个值
      • application/x-www-form-urlencoded
      • multipart/form-data
      • text/plain

浏览器发现是简单请求的跨域访问时会携带origin头信息,服务器端如果允许来自这个源的请求,就会响应一个Access-Control-Allow-Origin头,则本次跨域请求会成功。

特殊请求

不符合简单请求的条件,会被浏览器判定为特殊请求。

特殊请求会在正式通信之前,增加一次HTTP查询请求,称为”预检”请求(preflight)。

浏览器先询问服务器,当前网页所在的域名是否在服务器的许可名单之中,以及可以使用哪些HTTP动词和头信息字段。只有得到肯定答复,浏览器才会发出正式的XMLHttpRequest请求,否则就报错。

一个“预检”请求的样板:

1
2
3
4
5
6
7
8
OPTIONS /cors HTTP/1.1
Origin: http://manage.leyou.com
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: X-Custom-Header
Host: api.leyou.com
Accept-Language: en-US
Connection: keep-alive
User-Agent: Mozilla/5.0...

与简单请求相比,除了Origin以外,多了两个头:

  • Access-Control-Request-Method:接下来会用到的请求方式,比如PUT
  • Access-Control-Request-Headers:会额外用到的头信息

服务的收到预检请求,如果许可跨域,会发出响应:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
HTTP/1.1 200 OK
Date: Mon, 01 Dec 2008 01:15:39 GMT
Server: Apache/2.0.61 (Unix)
Access-Control-Allow-Origin: http://manage.leyou.com
Access-Control-Allow-Credentials: true
Access-Control-Allow-Methods: GET, POST, PUT
Access-Control-Allow-Headers: X-Custom-Header
Access-Control-Max-Age: 1728000
Content-Type: text/html; charset=utf-8
Content-Encoding: gzip
Content-Length: 0
Keep-Alive: timeout=2, max=100
Connection: Keep-Alive
Content-Type: text/plain

除了Access-Control-Allow-OriginAccess-Control-Allow-Credentials以外,这里又额外多出3个头:

  • Access-Control-Allow-Methods:允许访问的方式
  • Access-Control-Allow-Headers:允许携带的头
  • Access-Control-Max-Age:本次许可的有效时长,单位是秒,过期之前的ajax请求就无需再次预检

如果浏览器得到上述响应,则认定为可以跨域,后续就跟简单请求的处理是一样的了。

服务器端设置响应头

  • Access-Control-Allow-Origin:设置允许的来源
  • Access-Control-Allow-Method:设置允许的请求类型
  • Access-Control-Allow-Headers:设置默认不能拿到的字段( XMLHttpRequest对象的getResponseHeader()方法只能拿到6个基本字段 )

解决方案3

由于同源政策时浏览器给Ajax的限制,服务器端是不存在同源政策限制的。

跨域访问携带Cookie

在使用Ajax发送跨域请求时,默认情况下不会携带Cookie信息

实现

  • 客户端将XMLHttpRequest对象的withCredentials属性设置为ture,表示跨域请求时携带Cookie
  • 浏览器端设置Access-Control-Allow-Credentials:true, 表示允许客户端携带cookie

springmvc解决跨域问题

  • 方法1:使用CorssOrign注解

  • 方法2:注册一个CorsFilter

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;

@Configuration
public class GlobalCorsConfig {
@Bean
public CorsFilter corsFilter() {
//1.添加CORS配置信息
CorsConfiguration config = new CorsConfiguration();
//1) 允许的域,不要写*,否则cookie就无法使用了
config.addAllowedOrigin("http://manage.leyou.com");
//2) 是否发送Cookie信息
config.setAllowCredentials(true);
//3) 允许的请求方式
config.addAllowedMethod("OPTIONS");
config.addAllowedMethod("HEAD");
config.addAllowedMethod("GET");
config.addAllowedMethod("PUT");
config.addAllowedMethod("POST");
config.addAllowedMethod("DELETE");
config.addAllowedMethod("PATCH");
// 4)允许的头信息
config.addAllowedHeader("*");

//2.添加映射路径,我们拦截一切请求
UrlBasedCorsConfigurationSource configSource = new UrlBasedCorsConfigurationSource();
configSource.registerCorsConfiguration("/**", config);

//3.返回新的CorsFilter.
return new CorsFilter(configSource);
}
}

 

评论

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×