AJAX
可以在不刷新页面的情况下向服务器发送请求,允许根据用户的时间更新部分页面内容
缺点:
- 不能回退
- 存在跨域问题
- 对SEO优化不好,AJAX更新的部分在爬虫时爬不到
过程:
- 实例化(
new
)一个XMLHttpRequest
实例 - 调用
open('请求方式', "http://ip:port/xxx")
设置请求方式和请求地址 - 调用
send()
发送请求 - 处理
onreadystatechange
事件,如果readyState
准备状态为4,代表已完成请求,再判断一下状态status
是否为2xx
,针对这个再做处理 - 可以使用
response
属性获取全部的请求结果 - 请求的准备状态
readyState
含义-
// 0: 请求未初始化 // 1: 服务器连接已建立 // 2: 请求已接收 // 3: 正在处理请求 // 4: 请求已完成且响应已就绪
-
window.onload = function() {
var btn = document.getElementById("btn");
var box = document.getElementById("box");
btn.onclick = function() {
var xhr = new XMLHttpRequest();
xhr.open('GET', "http://127.0.0.1:5234/");
xhr.send();
xhr.onreadystatechange = function() {
// 第四个状态代表请求成功
if (xhr.readyState == 4) {
if (xhr.status >= 200 && xhr.status < 300) {
alert(xhr.status);
alert(xhr.responseText);
}
}
}
}
}
AJAX发送POST请求时,必须要在open
之后添加以下的请求头xhr.setRequestHeader("Content-type","application/x-www-form-urlencoded");
才能够正常的向服务器发送请求
btn.onclick = function() {
var xhr = new XMLHttpRequest();
xhr.open("POST", "http://127.0.0.1:5234/post");
// 必须写在open之后
xhr.setRequestHeader("Content-type","application/x-www-form-urlencoded");
xhr.send("name=baidu&sex=false");
xhr.onreadystatechange = function() {
if(xhr.readyState == 4 && xhr.status >= 200 && xhr.status < 300){
alert(xhr.response);
}
}
}
仿实时提示搜索关键词
<!DOCTYPE html>
<html lang="zh-cn">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/mdui@1.0.2/dist/css/mdui.min.css"/>
<script src="https://cdn.jsdelivr.net/npm/mdui@1.0.2/dist/js/mdui.min.js"></script>
<script type="text/javascript">
window.onload = function () {
var box = document.getElementById("box");
var text = document.getElementById("text");
// 内容发生改变时请求
text.oninput = function () {
var xhr = new XMLHttpRequest();
xhr.open("GET", "http://127.0.0.1:5234?wd=" + text.value);
xhr.send();
xhr.onreadystatechange = function () {
if (xhr.readyState == 4 && xhr.status >= 200 && xhr.status < 300) {
box.innerHTML = "";
var result = xhr.response;
result = result.substring(result.indexOf("s:") + 2, result.lastIndexOf("}"));
var resultList = JSON.parse(result);
for (var i = 0; i < resultList.length; i++) {
var a = document.createElement("a");
a.innerText = resultList[i];
a.href = "https://www.google.com/search?q=" + resultList[i];
a.onclick = function () {
text.value = p.innerText;
}
box.appendChild(a);
a.className = "mdui-list-item mdui-ripple";
box.append(document.createElement("br"));
}
}
}
}
}
</script>
<style>
#box {
width: 600px;
border: 1px solid black;
}
body{
padding: 20px;
}
</style>
</head>
<body>
<button id="btn">POST请求</button>
<br>
<!-- <input type="text" id="text" class="mdui-textfield-input" placeholder = "搜索内容"> -->
<div class="mdui-textfield mdui-textfield-floating-label">
<label class="mdui-textfield-label">搜索内容</label>
<input class="mdui-textfield-input" type="text" id="text" type="text"/>
</div>
<br>
<br>
<div id="box">
</div>
</body>
</html>
因为有跨域问题,使用spring作为后端
spring后端代码:
package com.moyok.ajax.service;
import com.moyok.ajax.util.GetRequest;
import org.springframework.stereotype.Controller;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.net.http.HttpResponse;
import java.util.Map;
@ResponseBody
@RequestMapping("/")
@Controller
@CrossOrigin
public class RequestController {
@RequestMapping("/")
public String healthCheck(@RequestParam Map<String, String> m){
return GetRequest.getRequest("https://sp0.baidu.com/5a1Fazu8AA54nxGko9WTAnF6hhy/su?wd=" + m.get("wd"));
}
}
工具类获取搜索到的内容
package com.moyok.ajax.util;
import lombok.SneakyThrows;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
public class GetRequest {
private GetRequest(){
}
@SneakyThrows
public static String getRequest(String url){
CloseableHttpClient httpClient = HttpClients.createDefault();
HttpGet httpGet = new HttpGet(url);
CloseableHttpResponse response = httpClient.execute(httpGet);
return EntityUtils.toString(response.getEntity(), "UTF-8");
}
}
依赖
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.13</version>
</dependency>
abort()取消请求
跨域
AJAX的请求要求必须是同源的,同源:协议、域名、端口号 必须完全相同,违背同源策略的请求称之为跨域
解决跨域的方法:
JSONP
JSON With Padding ,非官方的解决方案,只支持GET请求
在网页中有一些标签天然的支持跨域,例如<img>
、<iframe>
、<link>
、<script>
JSONP就是利用<script>
标签工作的
Axios
是前端最流行的ajax
请求库
可以在浏览器端和nodejs
中运行
可以直接调用axios()
函数发送请求
基本的请求方式:
const axios = require('axios');
axios({
method: "GET",
url: "http://localhost:5234/re"
}).then(response => {
console.log(response.data);
})
带有参数的请求
const axios = require('axios');
axios({
// 请求类型
method: "POST",
// 请求地址
url: "http://localhost:5234/post",
// 请求体的内容
data: {
name: "名字",
age: "10010",
sex: "true"
}
}).then(response => {
console.log(response.data);
})
在SpringBoot
中,可以给处理请求的方法的参数添加@RequestBody
注解表示接受请求过来的json
@PostMapping("/post")
public String post(@RequestBody Map<String, String> m) {
return m.toString();
}
使用request
方法
const axios = require('axios');
axios.request({
method: "POST",
url: "http://localhost:5234/post",
data: {
name: "名字",
age: "10010",
sex: "true"
}
}).then(response => {
console.log(response.data);
})
Post
请求,参数1为请求的url
字符串,参数2为数据(可选),参数3为配置(可选)
const axios = require('axios');
axios.post("http://localhost:5234/post", {
data: '数据',
node: "nodejs",
java: "数据结构"
}).then(response => { // 请求成功的回调函数
console.log(response.data);
})
也可以创建实例对象发送请求,在之后的请求中无需写全部的地址
const axios = require('axios');
const axiosInstance = axios.create({
baseURL: "http://localhost:5234"
});
axiosInstance.post("/post", {
name: "名称",
content: "何须浅碧深红色,自是花中第一流"
}).then(response => {
console.log(response.data);
})
自定义参数
axios.request({
url: "https://sp0.baidu.com/5a1Fazu8AA54nxGko9WTAnF6hhy/su",
method: "get",
params:{ // d
wd: "abcd"
}
}).then(response => {
console.log(response.data);
})
以后可以这么写
async function aaa (){
const result = await axios("http://liulongbin.top:3006/api/getbooks", {
method: "get"
});
console.log(result.data);
}
// 此时调用这个函数可以看到结果,无需再次使用then获取结果
aaa();
记住就可以
最终写法
async function aaa (){
const {data} = await axios("http://liulongbin.top:3006/api/getbooks", {
method: "get"
});
return data;
}
let re = aaa();
re.then(response => {
console.log(response);
})
由于axios
是异步的,如果用之前的方法在then中返回值会接收不到,所以只能采用这种方法
Q.E.D.