AJAX

可以在不刷新页面的情况下向服务器发送请求,允许根据用户的时间更新部分页面内容

缺点:

  • 不能回退
  • 存在跨域问题
  • 对SEO优化不好,AJAX更新的部分在爬虫时爬不到
image-20220131100026429

过程:

  • 实例化(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>
image-20220131132059972

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.


念念不忘,必有回响。