You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

整合Express与json-server时两类请求无法同时响应的问题求助

问题描述
  • 开发中转API,接收客户端请求转发至外部API,通过userData.json存储用户数据(含API密钥),包含外部API路由及/create-user路由(生成唯一API密钥并存入文件)
  • 本地开发阶段API运行正常,但部署至Vercel时,无服务器函数无法修改文件,因此尝试整合json-server解决存储问题
  • 当前本地运行异常:用node启动API可正常转发外部请求,但json-server相关请求返回404;用json-server启动则相反,两类请求无法同时正常工作
当前代码示例
// Import Express.js
import http from 'https' 
import express from 'express'
import jsonServer from 'json-server'
import path from 'path'

import {authenticateKey, createUser} from './api/apiAuth.js'
import {ixApi} from './ixApi.js' 

// This variable defines the port of your computer where the API will be available
const PORT = 3000

// This variable instantiate the Express.js library
const app = express()

app.use(express.json()); 
app.use(                
  express.urlencoded({
    extended: true,
  })
);  

// JSON Server module
const server = jsonServer.create();
const router = jsonServer.router("db.json");

//const router = jsonServer.router(path.join("", 'db.json'))

// Make sure to use the default middleware
const middlewares = jsonServer.defaults();

server.use(middlewares);

// Add this before server.use(router)
server.use(

  /**
   * Welcome message
   */
  app.get('/', (request, response) => {
    // The string we want to display on http://localhost:3000
    response.send('Welcome on the ix interface API!')
  }),

  /**
   * @function create-user - Creates new user
   */
  app.post('/create-user', authenticateKey, async (req, res) => {
    //create a new user with "user:Username"
    let username = req.body.username
    let appName = req.body.appName
    let userEmail = req.body.userEmail
    let IX_ACCOUNT_NAME = req.body.IX_ACCOUNT_NAME
    let IX_API_KEY = req.body.IX_API_KEY
    let user = await createUser(username, appName, userEmail, IX_ACCOUNT_NAME, IX_API_KEY, req, res)

    console.log('USER 1:')
    console.log(user)

    res.status(201).send({ data: user });
  }),


  /**
   * @function createInvoice - Creates invoice
   *
   * CALLED BY:
   * - 
   *
   * TO IMPROVE:
   * -
   */ 
  app.post('/create-invoice', authenticateKey, async (request, response) => {
    console.log(response.locals.ixCredentials)  
    console.log(request.body)
    console.log(request.body.invoiceData)

    const IX_ACCOUNT_NAME = response.locals.ixCredentials.IX_ACCOUNT_NAME
    const IX_API_KEY =  response.locals.ixCredentials.IX_API_KEY
    const invoiceData = request.body.invoiceData
    const items = request.body.invoiceData.items

    const creationRequest = () => {
      const response = new Promise ((resolve) => {
        var options = {
          "method": "POST",
          "hostname": IX_ACCOUNT_NAME + ".app.ix.com",
          "port": null,
          "path": "/invoices.json?api_key=" + IX_API_KEY,
          "headers": {
            "accept": "application/json",
            "content-type": "application/json"
          }
        };

        var req = http.request(options, function (res) {
          var chunks = [];

          res.on("data", function (chunk) {
            console.log('CHUNK')
            console.log(chunk.toString)
            chunks.push(chunk);
          });

          res.on("end", function () {
            var body = Buffer.concat(chunks);

            console.log('IX BODY:')
            console.log(body.toString());

            resolve(body.toString())
          });

          console.log(res.statusCode)

        })

        var itemsList = []                
        
        for (let i = 0; i < items.length; i++) {
          itemsList.push({ 
            name: items[i].name,
            description: items[i].description,
            unit_price: items[i].price,
            quantity: items[i].quantity,
          })

          console.log(itemsList)
        }

        req.write(JSON.stringify({ invoice: {
          date: invoiceData.date,
          due_date: invoiceData.due_date,
          client: {
              name: invoiceData.client.name,
              email: invoiceData.client.email,
              country: invoiceData.client.country,                        
              fiscal_id: invoiceData.client.vat,                        
              code: invoiceData.client.vat,
          },
          items: itemsList,
        }}));                                     

        req.on('error', function(err) {
          console.log('IX ERROR:')
          console.log(err)

          //return response.json({ success: false })                    
        });

        console.log('SENDING REQUEST:')  

        req.end();                  
      })

      console.log('RESPONSE')
      console.log(response)

      return response

    }

    const returnedData = await creationRequest()
      .then (response => { 
        console.log('INVOICE CREATED')     

        var obj = JSON.parse(response) 

        console.log(obj)     

        return obj
      });

    console.log('RETURNED DATA')
    console.log(returnedData)   

    return response.json(returnedData)     
  })
)

server.use(
    jsonServer.rewriter({
    "/api/*": "/$1",
  })
)

server.use(router);

/**
 * The code below starts the API with these parameters:
 * 1 - The PORT where your API will be available
 * 2 - The callback function (function to call) when your API is ready
 */
server.listen(PORT, () =>
  console.log(`The ix API is running on: http://localhost:${PORT}.`)
)

// Export the Server API
export {server}
解决方案

问题核心是你创建了两个独立的Express实例(app和server),并错误地将app的路由挂载到server上,导致路由逻辑冲突。正确的做法是将json-server作为Express的中间件,复用同一个服务器实例。

修改后的代码如下:

// Import dependencies
import http from 'https' 
import jsonServer from 'json-server'
import path from 'path'

import {authenticateKey, createUser} from './api/apiAuth.js'
import {ixApi} from './ixApi.js' 

const PORT = 3000

// 直接使用jsonServer创建Express实例,无需单独创建express()
const server = jsonServer.create();
const router = jsonServer.router("db.json");
const middlewares = jsonServer.defaults();

// 挂载请求解析中间件(json-server已封装bodyParser)
server.use(jsonServer.bodyParser());
// 如需自定义urlencoded配置,可单独添加:
// server.use(express.urlencoded({ extended: true }));

// 加载json-server默认中间件(静态文件、CORS等)
server.use(middlewares);

// 挂载自定义路由
server.get('/', (request, response) => {
  response.send('Welcome on the ix interface API!')
})

server.post('/create-user', authenticateKey, async (req, res) => {
  let username = req.body.username
  let appName = req.body.appName
  let userEmail = req.body.userEmail
  let IX_ACCOUNT_NAME = req.body.IX_ACCOUNT_NAME
  let IX_API_KEY = req.body.IX_API_KEY
  let user = await createUser(username, appName, userEmail, IX_ACCOUNT_NAME, IX_API_KEY, req, res)

  console.log('USER 1:')
  console.log(user)

  res.status(201).send({ data: user });
})

server.post('/create-invoice', authenticateKey, async (request, response) => {
  console.log(response.locals.ixCredentials)  
  console.log(request.body)
  console.log(request.body.invoiceData)

  const IX_ACCOUNT_NAME = response.locals.ixCredentials.IX_ACCOUNT_NAME
  const IX_API_KEY =  response.locals.ixCredentials.IX_API_KEY
  const invoiceData = request.body.invoiceData
  const items = request.body.invoiceData.items

  const creationRequest = () => {
    // 修复变量名冲突:原Promise内部使用了response变量,与外部参数重名
    return new Promise ((resolve) => {
      var options = {
        "method": "POST",
        "hostname": IX_ACCOUNT_NAME + ".app.ix.com",
        "port": null,
        "path": "/invoices.json?api_key=" + IX_API_KEY,
        "headers": {
          "accept": "application/json",
          "content-type": "application/json"
        }
      };

      var req = http.request(options, function (res) {
        var chunks = [];

        res.on("data", function (chunk) {
          console.log('CHUNK')
          console.log(chunk.toString)
          chunks.push(chunk);
        });

        res.on("end", function () {
          var body = Buffer.concat(chunks);
          console.log('IX BODY:')
          console.log(body.toString());
          resolve(body.toString())
        });

        console.log(res.statusCode)
      })

      var itemsList = []                
      for (let i = 0; i < items.length; i++) {
        itemsList.push({ 
          name: items[i].name,
          description: items[i].description,
          unit_price: items[i].price,
          quantity: items[i].quantity,
        })
      }

      req.write(JSON.stringify({ invoice: {
        date: invoiceData.date,
        due_date: invoiceData.due_date,
        client: {
            name: invoiceData.client.name,
            email: invoiceData.client.email,
            country: invoiceData.client.country,                        
            fiscal_id: invoiceData.client.vat,                        
            code: invoiceData.client.vat,
        },
        items: itemsList,
      }}));                                     

      req.on('error', function(err) {
        console.log('IX ERROR:')
        console.log(err)
      });

      req.end();                  
    })
  }

  const returnedData = await creationRequest()
    .then (data => { 
      console.log('INVOICE CREATED')     
      return JSON.parse(data)
    });

  console.log('RETURNED DATA')
  console.log(returnedData)   
  return response.json(returnedData)     
})

// 给json-server路由加前缀,避免与自定义路由冲突
server.use('/api', router);

// 启动服务器
server.listen(PORT, () =>
  console.log(`The ix API is running on: http://localhost:${PORT}.`)
)

export {server}

关键修改说明

  1. 移除独立的express()实例,直接使用jsonServer.create()返回的Express实例,确保路由和中间件都在同一个服务器上运行
  2. 使用jsonServer.bodyParser()替代原有的express.json()和express.urlencoded(),简化中间件配置
  3. 将自定义路由直接挂载到server实例上,而非错误地传入server.use()的参数列表
  4. 给json-server的路由添加/api前缀,避免与自定义路由(如/create-user)冲突,可根据需求调整前缀
  5. 修复了creationRequest函数中的变量名冲突问题,避免逻辑异常

内容的提问来源于stack exchange,提问作者jjm

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 21:18:07