axios GET请求获取API数据EJS渲染时报ERR_HTTP_HEADERS_SENT错误
报错根因
Error [ERR_HTTP_HEADERS_SENT] 是因为同一次请求触发了两次响应:
- 第一次是axios请求成功回调里的
res.json(response.data),已经把接口数据作为响应发回给客户端,响应头已经发送完成 - 紧接着同步执行的
res.render('produtos2', {product: productApi})尝试第二次发送响应,自然会触发报错。
你调整后的第二版代码只保留了res.json()逻辑,根本没有执行EJS渲染,自然能返回接口数据但出不来视图。另外初始写法还有个问题:axios.get()返回的是Promise对象,你没等异步请求resolve拿到实际数据就执行渲染,传给EJS模板的根本不是接口返回的真实数据。
正确实现代码
推荐用async/await写法,逻辑更清晰,记得加错误捕获:
app.get("/test", async (req, res, next) => { try { // 等待接口请求完成,拿到真实返回数据 const apiRes = await axios.get("https://swapi.dev/api/people/1") const productData = apiRes.data // 拿到数据后再执行视图渲染,整个请求只发这一次响应 res.render('produtos2', {product: productData}) } catch (err) { next(err) } })
如果习惯Promise链式写法,用下面的版本也可以:
app.get("/test", (req, res, next) => { axios.get("https://swapi.dev/api/people/1") .then(response => { // 注意不要在这里写res.json,拿到数据后直接渲染 res.render('produtos2', {product: response.data}) }) .catch(err => next(err)) })
EJS模板调整
你调用的接口返回的是单个对象结构,不是数组,所以原来模板里的<%= product[0] %>写法不对,按对象属性取值即可,比如要展示人物名称就写<%= product.name %>,调整后模板:
<%- include('partials/header') %> teste view <%= product.name %> <%- include('partials/footer') %>
关键注意点
- 单次HTTP请求只能返回一次响应,要渲染EJS就不要同时写
res.json(),二者只能选一个 - 异步接口请求必须等待结果返回后,再把真实数据传给
res.render(),不能直接把Promise对象作为模板数据传入 - 渲染前先确认接口返回的数据结构,对象按属性取值、数组按下标取值,避免模板渲染报错
内容的提问来源于stack exchange,提问作者Ailton
相关产品推荐
相关产品推荐

