原生JavaScript实现AJAX:从Node.js后端到前端调用的完整指南

作者:慢半拍

时间:2026-10-31

浏览:653

本文详细讲解如何使用原生JavaScript实现AJAX功能,结合Node.js后端处理。内容涵盖服务器端路由与响应类型判断、单元测试配置、onload与onreadystatechange事件对比、请求头部设置、响应类型处理、缓存规避及IE兼容性问题,提供完整代码示例与最佳实践。

文章目录

Node.js后端环境搭建与路由处理

本文使用Node.js作为后端环境,实现浏览器与服务器的全栈JavaScript交互。Node.js代码简洁高效,建议读者在GitHub下载示例项目并关注相关开发动态。以下是服务器端的核心代码实现:


// app.js
var app = http.createServer(function(req, res){
  if(req.url.indexOf("/scripts/") >= 0){
    render(req.url.slice(1), "application/javascript", httpHandler);
  } else if(req.headers['x-requested-with'] === 'XMLHttpRequest'){
    // Send Ajax response
  } else{
    render('views/index.html', 'text/html', httpHandler);
  }
}

该代码段通过检查请求URL来确定返回内容类型。若请求路径包含scripts目录,服务器将返回Content-Type为application/javascript的文件;若请求头中x-requested-with字段设为XMLHttpRequest,则判定为Ajax请求并返回对应数据;其他情况默认返回views/index.html页面。

接下来深入解析上述代码中处理Ajax请求的关键部分。在Node.js环境中,render函数和httpHandler函数负责处理主要的逻辑流程:


// app.js
function render(path, contentType, fn) {
  fs.readFile(__dirname + '/' + path, 'utf-8', function (err, str) {
    fn(err, str, contentType);
  });
}
var httpHandler = function (err, str, contentType) {
  if (err) {
    res.writeHead(500, {'Content-Type': 'text/plain'});
    res.end('An error has occured: ' + err.message);
  } else {
    res.writeHead(200, {'Content-Type': contentType});
    res.end(str);
  }
};

render函数异步读取请求文件内容,并将httpHandler函数引用作为回调传递。httpHandler函数检查error对象是否存在(例如文件无法打开时),同时指定正确的Content-Type,确保服务器返回的文件拥有合适的HTTP状态码和Content-Type。

API单元测试配置与运行

测试API 为确保后端API正常运行,编写单元测试。测试过程中使用supertest和mocha库辅助验证。


// test/app.request.js
it("responds with html", function(done){
  request(app)
    .get("/")
    .expect("Content-Type", /html/)
    .expect(200, done);
});
it('responds with javascript', function (done) {
request(app)
  .get('/scripts/index.js')
  .expect('Content-Type', /javascript/)
  .expect(200, done);
});
it('responds with json', function (done) {
request(app)
  .get('/')
  .set('X-Requested-With', 'XMLHttpRequest')
  .expect('Content-Type', /json/)
  .expect(200, done);
});

这些测试确保应用对不同请求返回正确的Content-Type和HTTP状态码。安装相关依赖后,可通过npm test命令运行测试。

前端界面与事件处理机制

界面 查看用户界面的HTML代码结构:


// views/index.html
<h1>Vanilla Ajax without jQuery</h1>
<button id="retrieve" data-url="/">Retrieve</button>
<p id="results"></p>

上述HTML代码结构简洁。所有核心交互逻辑均在JavaScript中实现。

onreadystate vs onload 查阅Ajax相关权威资料时,常可见onreadystate回调函数。该回调需通过嵌套if或多case语句处理,记忆难度较大。现对比onreadystate与onload事件机制。


(function() {
  var retrieve = document.getElementById('retrieve'),
    results = document.getElementById('results'),
    toReadyStateDescription = function(state) {
      switch (state) {
        case 0:
          return 'UNSENT';
        case 1:
          return 'OPENED';
        case 2:
          return 'HEADERS_RECEIVED';
        case 3:
          return 'LOADING';
        case 4:
          return 'DONE';
        default:
          return '';
      }
    };
  retrieve.addEventListener('click', function(e) {
    var oReq = new XMLHttpRequest();
    oReq.onload = function() {
      console.log('Inside the onload event');
    };
    oReq.onreadystatechange = function() {
      console.log('Inside the onreadystatechange ev![此处输入图片的描述][1]ent with readyState: ' +
        toReadyStateDescription(oReq.readyState));
    };
    oReq.open('GET', e.target.dataset.url, true);
    oReq.send();
  });
}());

上述代码在控制台输出如下信息:

Node.js后端环境搭建与路由处理

onreadystatechange事件在请求各阶段触发,包括请求前和请求末。根据文档,onload事件仅在请求成功时触发。作为常见API,onload易于掌握,而onreadystatechange可作为向后兼容的备用方案。优先推荐使用onload事件,其功能与jQuery的success回调类似。

请求头部设置与版本控制

###设置请求头部 jQuery默认协助设置请求头部,使后端能识别Ajax请求。通常后端不关心GET请求来源,只需返回正确响应。当同一Web API需同时返回Ajax或HTML数据时,此机制尤为重要。以下展示如何通过原生JavaScript设置请求头部:


var oReq = new XMLHttpRequest();
oReq.open('GET', e.target.dataset.url, true);
oReq.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
oReq.send();

同时在Node.js中进行相应检测:


 


if (req.headers['x-requested-with'] === 'XMLHttpRequest') {
  res.writeHead(200, {'Content-Type': 'application/json'});
  res.end(JSON.stringify({message: 'Hello World!'}));
}

如示例所示,原生Ajax是灵活且现代化的前端API。利用请求头部可实现多种功能,如版本控制。例如,希望Web API支持多版本但不通过URL区分,可通过设置请求头部由客户端选择所需版本。设置方式如下:


oReq.setRequestHeader('x-vanillaAjaxWithoutjQuery-version', '1.0');

后端相应代码实现:


 


if (req.headers['x-requested-with'] === 'XMLHttpRequest' &&
  req.headers['x-vanillaajaxwithoutjquery-version'] === '1.0') {
  // Send Ajax response
}

利用Node.js提供的headers对象进行检测。需注意读取时统一使用小写字母。

响应类型处理与浏览器兼容性

响应类型 为何responseText返回字符串而非可直接操作的JSON?因未设置合适的responseType属性。该Ajax属性明确告知前端API期望的服务器返回数据类型,需充分利用:


var oReq = new XMLHttpRequest();
oReq.onload = function (e) {
  results.innerHTML = e.target.response.message;
};
oReq.open('GET', e.target.dataset.url, true);
oReq.responseType = 'json';
oReq.send();

如此无需将返回纯文本解析为JSON,可直接告知API期望的数据类型。该特性获最新主流浏览器广泛支持。jQuery自动转换适当类型,而现代原生JavaScript亦提供便捷等效方法。原生Ajax已支持XML等其他响应类型。

遗憾的是,IE11及之前版本不支持xhr.responseType='json'。尽管该特性在Microsoft Edge中已得到支持,且相关Bug报告已提交近两年,相信Microsoft团队正持续改进浏览器。期待Microsoft Edge(原Project Spartan)兑现承诺。 针对IE问题,可采用以下解决方案:


oReq.onload = function (e) {
  var xhr = e.target;
  if (xhr.responseType === 'json') {
    results.innerHTML = xhr.response.message;
  } else {
    results.innerHTML = JSON.parse(xhr.responseText).message;
  }
};

缓存规避策略与总结

避免缓存 浏览器默认缓存Ajax请求的特性常被忽略,例如IE默认如此。曾因此导致Ajax请求未执行而耗费数小时排查。幸运的是,jQuery默认清除浏览器缓存。纯Ajax实现同样简单:


var bustCache = '?' + new Date().getTime();
oReq.open('GET', e.target.dataset.url + bustCache, true);

查阅jQuery文档可知,jQuery在每个GET请求后追加时间戳作为查询字符串,使请求唯一化以避免浏览器缓存。触发HTTP Ajax请求时,可见类似如下请求格式:

Node.js后端环境搭建与路由处理

至此,无其他复杂操作。

总结 希望读者喜欢这篇关于原生Ajax的文章。过去Ajax曾被视为复杂技术,但本文已覆盖其所有基础知识。

最后,提供一个简洁的Ajax调用方式示例:


var oReq = new XMLHttpRequest();
oReq.onload = function (e) {
  results.innerHTML = e.target.response.message;
};
oReq.open('GET', e.target.dataset.url + '?' + new Date().getTime(), true);
oReq.responseType = 'json';
oReq.send();

实用工具推荐

电子包浆

绿化、压缩、噪点和虚拟水印,自由调节做旧程度。

使用 ›
图片压缩

选择画质和输出格式,预览压缩前后的大小。

使用 ›
相关文章