杰瑞科技汇

Java中如何精准判断AJAX请求?

核心方法:检查 X-Requested-With 请求头

这是目前最通用、最标准的判断方法,绝大多数现代的 JavaScript 框架(如 jQuery、axios、fetch)在发送 AJAX 请求时,都会自动添加一个 X-Requested-With: XMLHttpRequest 的请求头。

Java中如何精准判断AJAX请求?-图1
(图片来源网络,侵删)

在原生 Servlet 中判断

如果你使用的是原生的 Java Servlet,可以通过 HttpServletRequest 对象的 getHeader() 方法来检查。

import javax.servlet.http.HttpServletRequest;
public class AjaxUtils {
    // 定义一个常量,避免硬编码,方便维护
    public static final String AJAX_HEADER = "X-Requested-With";
    public static boolean isAjaxRequest(HttpServletRequest request) {
        // 获取请求头
        String requestedWith = request.getHeader(AJAX_HEADER);
        // 如果请求头不为空,且值为 XMLHttpRequest,则认为是 AJAX 请求
        return "XMLHttpRequest".equals(requestedWith);
    }
}

如何使用:

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet("/api/data")
public class DataServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        if (AjaxUtils.isAjaxRequest(req)) {
            // 是 AJAX 请求,返回 JSON 数据
            resp.setContentType("application/json");
            resp.setCharacterEncoding("UTF-8");
            resp.getWriter().write("{\"message\": \"这是从 AJAX 请求返回的数据\"}");
        } else {
            // 不是 AJAX 请求(比如是普通的页面跳转),返回 HTML 或重定向
            resp.setContentType("text/html");
            resp.setCharacterEncoding("UTF-8");
            resp.getWriter().write("<h1>这是一个普通请求</h1>");
        }
    }
}

在 Spring MVC 中判断

Spring MVC 提供了更便捷的方式来处理这个问题,推荐使用 @RequestMappingproduces 属性。

使用 produces 属性(推荐)

Java中如何精准判断AJAX请求?-图2
(图片来源网络,侵删)

这种方式更符合 RESTful 风格,它直接定义了该接口能返回的响应内容类型,前端 AJAX 请求通常期望接收 JSON,而普通请求期望接收 HTML。

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.ModelAndView;
@RestController // @RestController 中的所有方法默认都返回 JSON,相当于都加了 @ResponseBody
public class MyAjaxController {
    // 这个方法会处理 AJAX 请求
    @GetMapping(value = "/api/user", produces = "application/json")
    public User getUserForAjax() {
        User user = new User("张三", 30);
        return user; // Spring MVC 会自动将对象序列化为 JSON 并返回
    }
    // 这个方法会处理普通请求,返回一个视图名
    @GetMapping("/page/user")
    public ModelAndView getUserPage() {
        ModelAndView mav = new ModelAndView("userPage"); // 返回一个 HTML 页面
        mav.addObject("username", "李四");
        return mav;
    }
}
// 一个简单的 POJO
class User {
    private String name;
    private int age;
    // ... 构造器、getter 和 setter
}

手动检查请求头

如果你仍然想手动检查,可以通过 HttpServletRequest 参数。

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
@RestController
public class ManualCheckController {
    @GetMapping("/api/manual-check")
    public String check(HttpServletRequest request) {
        if (AjaxUtils.isAjaxRequest(request)) {
            return "这是一个 AJAX 请求的响应";
        } else {
            return "这是一个普通请求的响应";
        }
    }
}

其他方法(作为补充)

虽然 X-Requested-With 是最主流的,但在某些特定场景下,你也可以使用其他方法。

检查 Accept 请求头

AJAX 请求通常会在 Accept 头中声明它期望接收的数据类型,application/jsonapplication/xml,而浏览器直接请求时,Accept 头会包含 text/html

public static boolean isAjaxRequestByAccept(HttpServletRequest request) {
    String acceptHeader = request.getHeader("Accept");
    // Accept 头中包含 application/json,则很可能是 AJAX 请求
    return acceptHeader != null && acceptHeader.contains("application/json");
}

注意: 这种方法不如 X-Requested-With 可靠,因为一个普通请求也可能要求接收 JSON 数据,但它可以作为一个辅助判断的依据。

检查 Content-Type 请求头

这个方法适用于 POST/PUT 请求,AJAX 请求在发送数据(如 JSON、Form Data)时,会设置 Content-Type

  • 发送 JSON 数据:Content-Type: application/json
  • 发送表单数据:Content-Type: application/x-www-form-urlencoded
public static boolean isAjaxRequestByContentType(HttpServletRequest request) {
    String contentType = request.getContentType();
    // Content-Type 是 application/json,则认为是 AJAX 请求
    return contentType != null && contentType.contains("application/json");
}

注意: 这个方法不适用于 GET 请求,因为 GET 请求没有请求体,也就没有 Content-Type,它只能作为 POST/PUT 请求的辅助判断。


方法 优点 缺点 适用场景
检查 X-Requested-With 最标准、最可靠,被所有主流 JS 框架支持 某些老旧的 AJAX 库或自定义脚本可能不包含此头 所有场景下的首选和推荐方法
检查 Accept 可以判断期望的响应格式 可靠性较低,普通请求也可能要求 JSON 作为辅助判断,或在无法控制请求头时使用
检查 Content-Type 对于 POST/PUT 请求判断准确 不适用于 GET 请求,需要手动判断 主要用于处理 AJAX 提交的数据,如文件上传

最终建议:

  1. 首选 X-Requested-With:在你的工具类中封装一个 isAjaxRequest 方法,基于此进行判断,这是最健壮、最通用的方案。
  2. 在 Spring 中拥抱约定:优先使用 Spring MVC 的 produces 属性来区分返回 JSON 还是 HTML,让框架帮你处理大部分逻辑,代码更清晰。
  3. 组合使用:在非常复杂的场景下,可以结合 X-Requested-WithAccept/Content-Type 进行更精确的判断,但通常没有必要。

前端示例(jQuery)

为了让你更完整地理解,这里给出一个使用 jQuery 发送 AJAX 请求的例子,你会看到它确实会带上 X-Requested-With 头。

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">AJAX 请求示例</title>
    <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
</head>
<body>
    <h1>测试 AJAX 请求</h1>
    <button id="ajaxBtn">发送 AJAX 请求</button>
    <button id="normalBtn">发送普通请求</button>
    <div id="result"></div>
    <script>
        $(document).ready(function() {
            // 使用 jQuery 发送 AJAX 请求
            $("#ajaxBtn").click(function() {
                $.ajax({
                    url: "/api/data",
                    type: "GET",
                    success: function(response) {
                        $("#result").html("<pre>" + JSON.stringify(response, null, 2) + "</pre>");
                    },
                    error: function() {
                        $("#result").text("请求失败");
                    }
                });
            });
            // 发送普通请求(页面跳转或刷新)
            $("#normalBtn").click(function() {
                window.location.href = "/page/user"; // 假设这个路径处理普通请求
            });
        });
    </script>
</body>
</html>

当你点击“发送 AJAX 请求”按钮时,浏览器的开发者工具(Network 标签页)中会看到对 /api/data 的请求,其请求头中包含了 X-Requested-With: XMLHttpRequest,而点击“发送普通请求”则没有,这就是后端能够区分它们的依据。

分享:
扫描分享到社交APP
上一篇
下一篇