XMLHttpRequest请求后返回HTML内script脚本不生效的解决方法
问题根因
你现有代码跑不通的直接原因是setInnerHTML方法里的API调用错误:DOM元素根本没有setAttributes这个复数命名的方法,正确的属性设置方法是单数形式的setAttribute,所以你动态创建的script标签属性复制逻辑完全没生效,脚本自然不会执行。
就算你把这个API名改对,这种靠AJAX拉取整段带script的HTML、再手动替换script标签强制执行的思路也非常不推荐:本质是在页面里动态执行远程返回的任意代码,存在极大的XSS安全隐患,同时还会出现执行时序不可控、DOM节点找不到、调试困难等一堆问题。
最优无刷新实现方案
彻底抛弃“拉取带渲染逻辑的HTML片段再强制执行脚本”的思路,做最基础的前后端职责拆分:
- 后端接口只返回纯JSON格式的搜索结果数据,不要返回混杂script标签的HTML内容
- 所有渲染逻辑全部放在主页面(index.html)中,拿到接口返回的JSON数据后直接在当前页面完成DOM拼接、渲染到
demo容器 - 全程不需要动态插入、执行远程脚本,没有安全风险,逻辑可控调试方便
具体落地代码
1. 后端接口调整
把原来ajax_info.html里硬编码的searchResults数据抽出来,做成专门的搜索接口(比如路径设为/api/search),接口接收POST请求,直接返回纯JSON格式的搜索结果,结构参考:
{ "response": { "docs": [ { "es_title": "搜索结果标题", "es_description": "搜索结果摘要描述", "author": "作者名", "site": "来源站点", "es_date": "2024-05-20" } ] } }
2. 主页面逻辑调整
把原来写在ajax_info.html里的渲染逻辑移到index.html中,改造后的loadDoc方法如下:
function loadDoc() { const resultContainer = document.getElementById("demo"); const xhttp = new XMLHttpRequest(); xhttp.onreadystatechange = function() { if (this.readyState !== XMLHttpRequest.DONE) return; if (this.status !== 200) { resultContainer.innerHTML = "<div class='text-danger p-3'>搜索结果加载失败,请重试</div>"; return; } try { // 解析接口返回的JSON数据 const searchResults = JSON.parse(this.responseText); const docList = searchResults.response.docs; let resultHtml = ""; // 拼接结果DOM for (let i = 0; i < docList.length; i++) { const item = docList[i]; resultHtml += ` <div class='p-3 border rounded-3'> <a href=''> <strong class='text-primary largeText'>${item.es_title}</strong> </a> <div class='largeText'>${item.es_description}</div> <div>${item.author}</div> <div>${item.site}</div> <div>${item.es_date}<a class='text-success'> ${item.site}</a></div> </div> `; } // 一次性把渲染好的内容插入容器 resultContainer.innerHTML = resultHtml; } catch (err) { console.error("结果解析出错:", err); resultContainer.innerHTML = "<div class='text-danger p-3'>搜索结果格式异常,请稍后重试</div>"; } }; xhttp.open("POST", "/api/search", true); // 传搜索参数的时候设置对应请求头 xhttp.setRequestHeader("Content-Type", "application/json"); xhttp.send(JSON.stringify({ keyword: document.getElementById("searchInput").value.trim() })); }
临时兼容方案(不推荐生产使用)
如果你暂时不想调整架构,非要沿用现有拉取ajax_info.html的逻辑,先把两个问题修复:
- 把代码里的
newScript.setAttributes改成newScript.setAttribute,修正API调用错误 - 确保
ajax_info.html里id为demo2的div节点和script标签一起被返回,不然脚本执行时找不到对应DOM节点会直接中断
风险提示:这种方案会直接执行接口返回的任意脚本代码,一旦接口内容被篡改,就会被注入恶意代码执行,存在严重安全隐患。
内容的提问来源于stack exchange,提问作者SerikTheCzar
相关产品推荐
相关产品推荐

