1、AJAX 简介
- AJAX 全称为 Asynchronous JavaScript And XML(中文名:阿贾克斯),就是异步的 JS 和 XML。
- AJAX 不是新的编程语言,而是一种将现有的标准组合在一起使用的新方式。
- AJAX 可以在浏览器中向服务器发送异步请求,最大的优势:无刷新获取数据。
- AJAX 的两个主要功能使您可以执行以下操作:
-
向服务器发出请求,而无需重新加载页面
-
从服务器接收和处理数据
2、AJAX 的优缺点
2.1 AJAX 的优点
- 可以无需刷新页面而与服务器端进行通信。
- 允许你根据用户事件来更新部分页面内容。
2.2 AJAX 的缺点
- 没有浏览历史,不能回退。
- 存在跨域问题(同源)。出于安全原因,浏览器不允许跨域访问。也就是当前网页和 AJAX 要请求的网页地址要在同一个域名下。
-
SEO(搜索引擎优化) 不友好。因为源代码没有具体信息,而是通过 AJAX 异步获取数据,无法被爬虫获取到数据
3、AJAX 的工作原理
JavaScript 使用一个 XMLHttpRequest(核心对象) 对象向服务器发出 HTTP 请求并作为响应接收数据。所有现代浏览器(Chrome,Firefox,IE7 +,Safari,Opera)都支持该 XMLHttpRequest 对象。
具体步骤:
网页中发生了一个事件(即页面已加载或单击了某些按钮)
JavaScript 创建 XMLHttpRequest 对象
XMLHttpRequest 对象将请求发送到 Web 服务器
服务器处理请求
服务器将响应发送回网页
响应由 JavaScript 读取
JavaScript 更新 HTML DOM
4、温习 HTTP 协议
HTTP(Hypertext Transport Protocol,超文本传输协议)详细规定了浏览器和万维网服务器之间互相通信的规则。主要包括:请求报文、响应报文。我们温习一下它们的格式与参数
4.1 请求报文
- 请求行:主要包括请求类型(GET、POST使用居多)、URL 路径、协议版本(一般是 HTTP/ 1.1)
- 请求头:主要包括 Host、Cookie、Content-Type、User-Agent,都是键值对形式
- 空行:空行固定
- 请求体:GET 类型的请求体是空的,POST 类型的请求体可以为空,也可以不为空
4.2 响应报文
- 响应行:主要包括协议版本(HTTP/1.1)、响应状态码(比如200、404、500)、响应字符串(比如 OK)
- 响应头:Content-Type(text/html;charset=utf-8)、Content-length、Content-encoding
- 空行:空行固定
- 响应体:服务端返回的具体响应数据(日常开发用得最多的内容)
5、后台服务应用准备
要学习 AJAX 需要后台服务,这里我们以熟悉的 Java 为例。在企业开发中,目前大多数还是 Java 后台。这里要求对 Java 有一定的了解,并且把 JDK 环境、Maven 环境、IDEA 环境都准备好。
代码结构比较简单,如截图:
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.study</groupId>
<artifactId>Ajax</artifactId>
<version>1.0-SNAPSHOT</version>
<!-- SpringBoot 版本 -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.12.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!--web支持-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
</project>
application.yml (此配置非必须,如果不配置服务器端口号,默认 8080)
# 配置服务器端口号
server:
port: 8000
AjaxApp
package com.study;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* @author CSDN 流放深圳
* @description 主应用程序
* @signature 让天下没有难写的代码
* @create 2024-03-24 下午 4:03
*/
@SpringBootApplication
public class AjaxApp {
public static void main(String[] args) {
SpringApplication.run(AjaxApp.class, args);
}
}
AjaxController
package com.study.controller;
import org.springframework.web.bind.annotation.*;
import java.util.HashMap;
import java.util.Map;
/**
* @author CSDN 流放深圳
* @description
* @signature 让天下没有难写的代码
* @create 2024-03-24 下午 4:05
*/
@RestController
public class AjaxController {
/**
* Get 请求
* @return
*/
@GetMapping("/helloWorld")
public String helloWorld(){
String result = "Hello,Ajax!欢迎来到新的学习基地!";
return result;
}
/**
* Post 请求
* @return
*/
@PostMapping("/say")
public String say(){
String result = "纸上得来终觉浅,绝知此事要躬行!";
return result;
}
/**
* 根据 id 获取信息
* @param id
* @return
*/
@GetMapping("/getById")
public Map<String, String> getById(@RequestParam Integer id) {
Map<String, String> map = new HashMap<>();
if(id == 1){
map.put("userName", "刘德华");
map.put("introduction", "我是1号选手,我来自香港");
}else if(id == 2){
map.put("userName", "周杰伦");
map.put("introduction", "我是2号选手,我来自台湾");
try{
Thread.sleep(3000);//模拟超时,3秒后响应接口
}catch (Exception e){
System.out.println("3秒后响应接口请求");
}
}
return map;
}
/**
* 根据 userName 获取数据
* @param userName
* @return
*/
@PostMapping("/getByName")
public Map<String, String> getByName(@RequestParam String userName) {
Map<String, String> map = new HashMap<>();
if("周星驰".equals(userName)){
map.put("userName", "周星驰");
map.put("introduction", "曾经有一份真挚的爱情摆在我面前,我没有珍惜,等我失去的时候我才后悔莫及,人世间最痛苦的事莫过于此。如果上天能够给我一个再来一次的机会,我会对那个女孩子说三个字:我爱你。如果非要在这份爱上加上一个期限,我希望是一万年。");
}else if("海明威".equals(userName)){
map.put("userName", "海明威");
map.put("introduction", "海的爱太深,时间太浅");
}
return map;
}
}
CorsConfig:注意这个配置类在前期学习必须要加上,否则会有跨域问题!
package com.study.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* @author CSDN 流放深圳
* @description 跨域处理配置类
* @signature 让天下没有难写的代码
* @create 2024-03-24 下午 4:15
*/
@Configuration
public class CorsConfig implements WebMvcConfigurer {
/**
* 允许跨域配置
* @param registry
*/
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")//匹配所有的请求
.allowedOrigins("*")//允许访问的客户端所有的域名
.allowedMethods("GET", "POST", "HEAD", "PUT", "DELETE", "OPTIONS")//允许列出的请求方式(其实就是标准的 HTTP 协议的请求方式)
.allowCredentials(true)//允许请求带有验证信息
.maxAge(3600)
.allowedHeaders("*");//允许客户端所有的请求头
}
}
如果不加这个跨域处理配置类,会出现如下错误:
Access to XMLHttpRequest at 'http://127.0.0.1:8000/helloWorld' from origin 'http://127.0.0.1:5500' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
OK,后台基础环境搭建完毕。启动后台服务,测试:http://127.0.0.1:8000/helloWorld
6、JavaScript 原生 AJAX
6.1 AJAX 入门
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>JavaScript 原生 AJAX</title>
<script>
window.onload = function(){//文档加载完成后执行
//获取文本域元素
let textarea = document.getElementById("textarea");
//需求1:点击按钮1,通过 GET 请求获取数据
let btn1 = document.getElementById("btn1");
//绑定按钮1事件
btn1.onclick = function(){
//1.创建 XMLHttpRequest 对象
let xhr = new XMLHttpRequest();
//2.初始化,设置请求方式和 url
xhr.open("GET", "http://127.0.0.1:8000/helloWorld");
//设置请求头信息(可以设置自定义请求头信息)
//xhr.setRequestHeader("Content-Type","text/plain;charset=UTF-8");
xhr.setRequestHeader("token","token123");//自定义会话的 token
//3.发送请求
xhr.send();
//4.事件绑定,处理服务器返回的结果。readyState 是 xhr 对象中的属性,表示状态有:0、1、2、3、4
xhr.onreadystatechange = function(){
if(xhr.readyState === 4){
//判断响应状态码:一般200开头的都是成功
/*
xhr.status:响应状态码
xhr.statusText:状态字符串
xhr.getAllResponseHeaders():所有响应头
xhr.response:响应体
*/
if(xhr.status >= 200 && xhr.status < 300){
//设置 textarea 的文本
textarea.innerHTML = xhr.response;
}
}
}
}
//需求2:点击按钮2,通过 POST 请求获取数据
let btn2 = document.getElementById("btn2");
btn2.onclick = function(){
let xhr = new XMLHttpRequest();
xhr.open("POST", "http://127.0.0.1:8000/say");
xhr.send();
xhr.onreadystatechange = function(){
if(xhr.status >= 200 && xhr.status < 300){
//设置 textarea 的文本
textarea.innerHTML = xhr.response;
}
}
}
}
</script>
</head>
<body>
<button id="btn1">按钮1 通过 GET 请求获取数据</button>
<button id="btn2">按钮2 通过 POST 请求获取数据</button>
<br><br>
<textarea id="textarea" cols="30" rows="10"></textarea>
</body>
</html>
效果:分别点击2个按钮,在文本框看到后台服务器返回的数据。
另外,我们设置的自定义请求头信息,也可以在浏览器中看到:
关于:XMLHttpRequest 对象的 readyState 状态枚举值:
XMLHttpRequest.readyState - Web API 接口参考 | MDN
值 | 状态 | 描述 |
---|---|---|
0 | UNSENT | 代理被创建,但尚未调用 open() 方法。 |
1 | OPENED | open() 方法已经被调用。 |
2 | HEADERS_RECEIVED | send() 方法已经被调用,并且头部和状态已经可获得。 |
3 | LOADING | 下载中;responseText 属性已经包含部分数据。 |
4 | DONE | 下载操作已完成或者已经失败。 |
6.2 处理 JSON 数据
JSON 格式的数据,已经成为企业级开发首选、必选的数据格式之一。因此掌握 JSON 格式的数据极其重要。
处理 JSON 格式有2种方式:
方式1:
- 设置 XMLHttpRequest 对象的返回体数据类型为 json(xhr.responseType = 'json';)
- 自动转换。如:const userName = xhr.response.userName;
方式2:手动对数据进行处理
let serverData = JSON.parse(xhr.response);
const userName = serverData.userName;
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>处理JSON数据</title>
<script>
window.onload = function(){//文档加载完成后执行
//获取文本域元素
let textarea = document.getElementById("textarea");
//需求1:点击按钮1,通过 GET 请求获取数据
let btn1 = document.getElementById("btn1");
//绑定按钮1事件
btn1.onclick = function(){
//1.创建 XMLHttpRequest 对象
let xhr = new XMLHttpRequest();
//设置响应体数据的类型
xhr.responseType = 'json';
//2.初始化,设置请求方式和 url
xhr.open("GET", "http://127.0.0.1:8000/getById?id=1");
//3.发送请求
xhr.send();
//4.事件绑定,处理服务器返回的结果。readyState 是 xhr 对象中的属性,表示状态有:0、1、2、3、4
xhr.onreadystatechange = function(){
if(xhr.readyState === 4){
if(xhr.status >= 200 && xhr.status < 300){
//方式1:手动对数据进行转换
/*
let serverData = JSON.parse(xhr.response);
const userName = serverData.userName;
const introduction = serverData.introduction;
textarea.innerHTML = "用户名:" + userName+",自我介绍:" + introduction;
*/
// 方式2:设置响应体数据类型,然后自动转换
const userName = xhr.response.userName;
const introduction = xhr.response.introduction;
textarea.innerHTML = "用户名:" + userName+",自我介绍:" + introduction;
}
}
}
}
}
</script>
</head>
<body>
<button id="btn1">GET 获取JSON数据</button>
<br><br>
<textarea id="textarea" cols="30" rows="10"></textarea>
</body>
</html>
效果:
6.3 解决 IE 浏览器缓存问题
问:什么是 IE 浏览器缓存问题?
答:IE 浏览器在处理 AJAX 请求时,会优先从本地判断是否有缓存,如果有,则不再向后台服务器获取数据,而是直接读取本地缓存数据。这对一些实时性要求高的场景来说,显然是不合理的。
问:如何解决 IE 浏览器缓存问题?
答:在请求头的 url 参数后面,增加一个当前时间戳的参数,传递到后台,保证每次请求都是新的请求。
如:xhr.open("GET", "http://127.0.0.1:8000/getById?id=1&t="+new Date());
6.4 处理请求超时和网络异常
一个良好的系统,都会有超时和网络异常的处理,给用户带来更好的体验,否则让用户一直干等,显然是不合理。那么 AJAX 是如何处理请求超时和网络异常的呢?
6.4.1 处理请求超时
//设置超时时间:2秒
xhr.timeout = 2000;
//超时回调函数
xhr.ontimeout = function(){
textarea.innerHTML = "啊噢,超时了,请您去别的地方逛逛吧!";
}
6.4.2 处理网络异常
//网络异常回调
xhr.onerror = function(){
textarea.innerHTML = "Sorry!网络异常,请您稍后重试!";
}
注意代码修改了,获取的 id=2,后台有设置线程3秒后响应请求:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>处理超时和网络异常</title>
<script>
window.onload = function(){//文档加载完成后执行
//获取文本域元素
let textarea = document.getElementById("textarea");
//需求1:点击按钮1,通过 GET 请求获取数据
let btn1 = document.getElementById("btn1");
//绑定按钮1事件
btn1.onclick = function(){
//1.创建 XMLHttpRequest 对象
let xhr = new XMLHttpRequest();
//设置响应体数据的类型
xhr.responseType = 'json';
//设置超时时间:2秒
xhr.timeout = 2000;
//超时回调函数
xhr.ontimeout = function(){
textarea.innerHTML = "啊噢,超时了,请您去别的地方逛逛吧!";
}
//网络异常回调
xhr.onerror = function(){
textarea.innerHTML = "Sorry!网络异常,请您稍后重试!";
}
//2.初始化,设置请求方式和 url
xhr.open("GET", "http://127.0.0.1:8000/getById?id=2");
//3.发送请求
xhr.send();
//4.事件绑定,处理服务器返回的结果。readyState 是 xhr 对象中的属性,表示状态有:0、1、2、3、4
xhr.onreadystatechange = function(){
if(xhr.readyState === 4){
if(xhr.status >= 200 && xhr.status < 300){
const userName = xhr.response.userName;
const introduction = xhr.response.introduction;
textarea.innerHTML = "用户名:" + userName+",自我介绍:" + introduction;
}
}
}
}
}
</script>
</head>
<body>
<button id="btn1">GET 获取JSON数据</button>
<br><br>
<textarea id="textarea" cols="30" rows="10"></textarea>
</body>
</html>
测试请求超时:
测试网络异常(把自己的浏览器的【网络】设置离线模式):
6.5 取消请求
使用 XMLHttpRequest 对象的 abort() 函数可以手动取消请求。
xhr.send();
xhr.abort();//取消请求
textarea.innerHTML = "取消了请求";
6.6 重复请求问题
问:什么是 AJAX 重复请求问题?
答:指的是同一个浏览器在某一段时间内发送了多次请求,且前几次的请求都失败了,这样会对后台服务器的压力是很大的,特别是并发量大的系统。因此需要处理重复请求的问题。
处理重复请求问题,可以按照如下步骤:
- 创建一个标识变量,判断是否正在发送请求。
- 如果判断该变量正在发送请求,则取消,并且重新创建一个新的请求。
- 如果请求发送成功且返回数据成功,修改标识变量的值。
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>重复请求问题</title>
<script>
window.onload = function(){//文档加载完成后执行
//获取文本域元素
let textarea = document.getElementById("textarea");
//需求1:点击按钮1,通过 GET 请求获取数据
let btn1 = document.getElementById("btn1");
//创建标识变量
let isSending = false;
//绑定按钮1事件
btn1.onclick = function(){
//1.创建 XMLHttpRequest 对象
let xhr = new XMLHttpRequest();
//判断标识变量
if(isSending){
xhr.abort();//取消请求
} else {
isSending = true;//设置为:正在请求
}
//设置响应体数据的类型
xhr.responseType = 'json';
//设置超时时间:5秒
xhr.timeout = 5000;
//超时回调函数
xhr.ontimeout = function() {
textarea.innerHTML = "啊噢,超时了,请您去别的地方逛逛吧!";
}
//网络异常回调
xhr.onerror = function(){
textarea.innerHTML = "Sorry!网络异常,请您稍后重试!";
}
//2.初始化,设置请求方式和 url
xhr.open("GET", "http://127.0.0.1:8000/getById?id=2");
//3.发送请求
xhr.send();
//4.事件绑定,处理服务器返回的结果。readyState 是 xhr 对象中的属性,表示状态有:0、1、2、3、4
xhr.onreadystatechange = function(){
if(xhr.readyState === 4){
//返回数据成功后,修改变量表示
isSending = false;
if(xhr.status >= 200 && xhr.status < 300){
const userName = xhr.response.userName;
const introduction = xhr.response.introduction;
textarea.innerHTML = "用户名:" + userName+",自我介绍:" + introduction;
}
}
}
}
}
</script>
</head>
<body>
<button id="btn1">GET 获取JSON数据</button>
<br><br>
<textarea id="textarea" cols="30" rows="10"></textarea>
</body>
</html>
效果:多次快速点击发送请求,后台服务器只接收到了第一个请求并返回数据,其它请求均被取消。
7、jQuery 发送 AJAX 请求
jQuery 发送 AJAX 请求主要有 3 个常用方法
- $.get()
- $.post()
- $.ajax()
其中,$.get() 和 $.post() 都是简单的请求方式,有 4 个参数:url,[data],[callback],[type]
url:请求的 url 地址
data:参数值(键值对格式)
callback:成功时的回调函数
type:返回的数据格式,xml, html, script, json, text, _default
$.ajax() 用于处理比较复杂的请求,它可以设置很多参数,比如:头部信息(headers,注意值不允许包含中文或者说是全角输入法的内容)、成功的回调(success)、失败的回调(error)、超时设置(timeout)等
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>jQuery 发送 AJAX</title>
<!-- 通过 CDN 引入 js库 -->
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.7.1/jquery.js"></script>
<script>
$(function () {//文档加载完成后执行
//发送 get 请求
$("#btn1").click(function () {
//get 请求有4个参数:url、参数(键值对)、回调函数、返回的数据类型
$.get("http://127.0.0.1:8000/getById", { id: 1 }, function (data) {
const userName = data.userName;
const introduction = data.introduction;
//在文本域中显示信息
$("#textarea").val("用户名:" + userName + ",自我介绍:" + introduction);
}, "json");
});
//发送 post 请求
$("#btn2").click(function () {
//post 请求也有4个参数:url、参数(键值对)、回调函数、返回的数据类型
$.post("http://127.0.0.1:8000/getByName", { "userName": "周星驰" }, function (data) {
const userName = data.userName;
const introduction = data.introduction;
//在文本域中显示信息
$("#textarea").val("用户名:" + userName + ",自我介绍:" + introduction);
}, "json");
});
//发送 ajax 请求。语法:jQuery.ajax(url,[settings])
$("#btn3").click(function () {
const myToken = "your token message";
const otherHeader = "can no be Chinese!";
$.ajax({
//url 地址
url: "http://127.0.0.1:8000/getByName",
//请求类型
type: "POST",
//头部信息(值不允许包含中文)
headers: {
token: myToken,
other: otherHeader
},
//参数
data: { "userName": "海明威" },
//响应体结果
dataType: "json",
//成功的回调
success: function (data) {
const userName = data.userName;
const introduction = data.introduction;
//在文本域中显示信息
$("#textarea").val("用户名:" + userName + ",自我介绍:" + introduction);
},
//失败的回调
error: function () {
$("#textarea").val("接口调用失败啦!");
},
//超时时间设置,单位:毫秒
timeout: 2000,
})
});
})
</script>
</head>
<body>
<h2>jQuery 发送 AJAX 请求</h2>
<button id="btn1">GET 请求</button>
<button id="btn2">POST 请求</button>
<button id="btn3">通用型方法 ajax</button>
<br><br>
<textarea id="textarea" cols="30" rows="10"></textarea>
</body>
</html>
效果:
8、axios 发送 AJAX 请求
axios 是现在前端比较流行和热门的 AJAX 工具库,也是 VUE 和 React 推荐的发送 AJAX 请求的工具包。关于 axios 后续博客会继续迭代。
axios 发送 AJAX 请求主要有 3 个常用方法(与 jQuery 类似):
- axios.get()
- axios.post()
- axios()
axios 在调用 AJAX 有一个 then() 函数用来接收返回数据
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>axios 发送 AJAX</title>
<!-- 通过 CDN 引入 js库 -->
<script src="https://cdn.bootcdn.net/ajax/libs/axios/1.5.0/axios.js"></script>
<script>
window.onload = function () {//文档加载完成后执行
//获取文本域元素
let textarea = document.getElementById("textarea");
//获取按钮
let btn1 = document.getElementById("btn1");
let btn2 = document.getElementById("btn2");
let btn3 = document.getElementById("btn3");
//配置 axios 基础请求路径
axios.defaults.baseURL = "http://127.0.0.1:8000";
//发送 get 请求
btn1.onclick = function () {
axios.get("/getById",
//参数
{
params: {
id: 1
},
//请求头信息
headers: {
token: "your token"
}
}
).then(response => {
//响应状态码
console.log(response.status);
//响应状态字符串
console.log(response.statusText);
//响应头信息
console.log(response.headers);
//响应体
console.log(response.data);
//在文本域显示信息
const userName = response.data.userName;
const introduction = response.data.introduction;
textarea.innerHTML = "用户名:" + userName + ",自我介绍:" + introduction;
}).catch(function (error) {
console.log(error);
});
};
//发送 post 请求
btn2.onclick = function () {
axios.post("/getByName",
//请求体参数
{
userName: "周星驰"
},
//其它参数
{
params: {
otherParam: "other"
},
//请求头参数
headers: {
//注意:后台服务该 POST 方法获取 userName 参数的格式是:@RequestParam String userName,需要增加头部 Content-Type 的配置
"Content-Type": "application/x-www-form-urlencoded;charset=utf-8",
"token": "your token"
}
}
).then(function (response) {
//响应状态码
console.log(response.status);
//响应状态字符串
console.log(response.statusText);
//响应头信息
console.log(response.headers);
//响应体
console.log(response.data);
//在文本域显示信息
const userName = response.data.userName;
const introduction = response.data.introduction;
textarea.innerHTML = "用户名:" + userName + ",自我介绍:" + introduction;
}).catch(function (error) {
console.log(error);
});
};
//发送 axios 请求
btn3.onclick = function () {
axios({
//请求方法
method: "POST",
//url
url: "/getByName",
//url参数
params: {
otherParam: "other"
},
//头信息
headers: {
//注意:后台服务该 POST 方法获取 userName 参数的格式是:@RequestParam String userName,需要增加头部 Content-Type 的配置
"Content-Type": "application/x-www-form-urlencoded;charset=utf-8",
"token": "your token"
},
//请求体参数
data: {
userName: "海明威"
}
}).then(response => {
//响应状态码
console.log(response.status);
//响应状态字符串
console.log(response.statusText);
//响应头信息
console.log(response.headers);
//响应体
console.log(response.data);
//在文本域显示信息
const userName = response.data.userName;
const introduction = response.data.introduction;
textarea.innerHTML = "用户名:" + userName + ",自我介绍:" + introduction;
}).catch(function (error) {
console.log(error);
});
}
}
</script>
</head>
<body>
<h2>axios 发送 AJAX 请求</h2>
<button id="btn1">GET 请求</button>
<button id="btn2">POST 请求</button>
<button id="btn3">通用型方法 axios</button>
<br><br>
<textarea id="textarea" cols="30" rows="10"></textarea>
</body>
</html>
需要注意的是,后台服务接收 POST 请求使用的方式是:
@RequestParam String userName
因此需要在 POST 请求的头部增加以下信息:
"Content-Type": "application/x-www-form-urlencoded;charset=utf-8"
否则会报错:
AxiosError {message: 'Request failed with status code 400', name: 'AxiosError', code: 'ERR_BAD_REQUEST', config: {…}, request: XMLHttpRequest, …}
效果:
9、跨域以及处理办法
9.1 什么是跨域?
当一个请求 url 的协议、域名、端口号三者之间任意一个与当前页面 url 不同即为跨域。
跨域也叫未被了“同源策略”,何为“同源”,即:协议、域名、端口号 必须完全相同。
9.2 如何解决跨域问题?
9.2.1 前端解决方案 —— JSONP
1、JSONP 是什么?
JSONP(JSON with Padding),是一个非官方的跨域解决方案,纯粹凭借程序员的聪明才智开发出来,只支持 get 请求。
2、JSONP 怎么工作的?
在网页有一些标签天生具有跨域能力,比如:img、link、iframe、script。JSONP 就是利用 script 标签的跨域能力来发送请求的。
3、JSONP 的使用
1、动态的创建一个 script 标签,如:
var script = document.createElement("script");
2、设置 script 的 src,设置回调函数,如:
script.src = "http://localhost:8000/yourAPI?callback=abc"; function abc(data) { alert(data.name); };
3、将 script 添加到 body 中
document.body.appendChild(script);
4、服务器中路由的处理
router.get("/yourAPI" , function (req , res) { console.log("收到请求"); var callback = req.query.callback; var obj = {name:"马云", world:"让天下没有难做的生意"} res.send(callback+"("+JSON.stringify(obj)+")"); });
9.2.2 后台服务解决方案 —— 跨源资源共享(CORS)
9.2.2.1 CORS 是什么?
CORS(Cross-Origin Resource Sharing),跨域资源共享。CORS 是官方的跨域解决方案,它的特点是不需要在客户端做任何特殊的操作,完全在服务器中进行处理,支持 get 和 post 和其它标准的 HTTP 请求。跨域资源共享标准新增了一组 HTTP 首部字段,允许服务器声明哪些源站通过浏览器有权限访问哪些资源。
官网:跨源资源共享(CORS) - HTTP | MDN
9.2.2.2 CORS 怎么工作的?
CORS 是通过设置一个响应头来告诉浏览器,该请求允许跨域,浏览器收到该响应以后就会对响应放行。
92.2.3 CORS 的使用
方式1:如果后台服务是 Java 语言写的,可以加上这个配置类(全局生效)
package com.study.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* @author CSDN 流放深圳
* @description 跨域处理配置类
* @signature 让天下没有难写的代码
* @create 2024-03-24 下午 4:15
*/
@Configuration
public class CorsConfig implements WebMvcConfigurer {
/**
* 允许跨域配置
* @param registry
*/
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")//匹配所有的请求
.allowedOrigins("*")//允许访问的客户端所有的域名
.allowedMethods("GET", "POST", "HEAD", "PUT", "DELETE", "OPTIONS")//允许列出的请求方式(其实就是标准的 HTTP 协议的请求方式)
.allowCredentials(true)//允许请求带有验证信息
.maxAge(3600)
.allowedHeaders("*");//允许客户端所有的请求头
}
}
方式2:增加自定义过滤器(全局生效)
package com.study.config;
import org.springframework.context.annotation.Configuration;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* @author CSDN 流放深圳
* @description 自定义跨域过滤器
* @create 2024-03-24 下午 6:15
* @since 1.0.0
*/
@Configuration
public class CorsFilter implements Filter {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletResponse response = (HttpServletResponse) servletResponse;
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, HEAD, OPTIONS, DELETE");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "x-requested-with");
response.setHeader("Access-Control-Expose-Headers", "content-disposition");
filterChain.doFilter(servletRequest, servletResponse);
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
Filter.super.init(filterConfig);
}
@Override
public void destroy() {
Filter.super.destroy();
}
}
方式3:在某个 Controller 类或者方法上加注解 @CrossOrigin
比如:
如果在类上加这个注解,表示这个类所有的方法都允许跨域;如果只在某个方法上加这个注解,表示只有该方法允许跨域。