Node.js 在没有输入标签的情况下收集表单数据时无法访问响应属性

Node.js cannot access response attribute when collecting form data without input tags

我正在尝试使用 Node.js 收集表单数据,但我无法检索它。

我有以下 add_device.html 页面:

<head>
    <script>
        /* Submit device type form when user clicks on div */
        $(function () {
            $(".device-form").on("click", function () {
                alert(this.device.value);
                $(".device-form").submit();
            });

        });
    </script>
</head>

<body>
    <div id="devices-available-container">

        <% deviceTypes.forEach(function(deviceType){ %>
        <div class="device-type-card">
            <form class="device-form" method="POST" action="/add_device">
                <div class="icon-and-text-container">
                    <div class="circle"><img class="icon" src="/img/device_types/<%=deviceType.device%>.png"
                            alt="Lightbulb icon"></div>
                    <div class="icon-description">
                        <button name="device" value="<%= deviceType.device %>"
                            type="text"><%= deviceType.device %></button>
                    </div>
                </div>
            </form>
        </div>
        <% }) %>

    </div>
</body>

并在 main.js(路线)中:

app.get("/add_device", function (req, res) {
        // query database to get all the books
        let sqlquery = "SELECT * FROM available_devices GROUP BY device order by device;";
        // execute sql query
        db.query(sqlquery, (err, result) => {
            if (err) {
                console.log(err);
                console.log(result);
                res.redirect("/");
            }
            //res.send(result)
            console.log(result);
            res.render("add_device.html", { deviceTypes: result });
        });
    });

    app.post('/add_device', function (req, res) {


        console.log(req.body.device);
        
    });

呈现的 HTML 是列表中的一系列项目。当用户单击包含项目图标和名称(图中黄色框)的 div 时,我希望提交 'form' 并将 'device' 属性设置为单击项目。

例如,如果用户在包含浴缸的 div 内单击,则应发布表单,并且 main.js、req.body.device 应等于 'bathtub'。

然而,由于某些原因,console.log(req.body.device);的结果是:

<ref *2> ServerResponse {
  _events: [Object: null prototype] { finish: [Function: bound resOnFinish] },
  _eventsCount: 1,
  _maxListeners: undefined,
  outputData: [],
  outputSize: 0,
  writable: true,
  destroyed: false,
  _last: false,
  chunkedEncoding: false,
  shouldKeepAlive: true,
  _defaultKeepAlive: true,
  useChunkedEncodingByDefault: true,
  sendDate: true,
  _removedConnection: false,
  _removedContLen: false,
  _removedTE: false,
  _contentLength: null,
  _hasBody: true,
  _trailer: '',
  finished: false,
  _headerSent: false,
  socket: <ref *1> Socket {
    connecting: false,
    _hadError: false,
    _parent: null,
    _host: null,
    _readableState: ReadableState {
      objectMode: false,
      highWaterMark: 16384,
      buffer: BufferList { head: null, tail: null, length: 0 },
      length: 0,
      pipes: [],
      flowing: true,
      ended: false,
      endEmitted: false,
      reading: true,
      sync: false,
      needReadable: true,
      emittedReadable: false,
      readableListening: false,
      resumeScheduled: false,
      errorEmitted: false,
      emitClose: false,
      autoDestroy: false,
      destroyed: false,
      errored: null,
      closed: false,
      closeEmitted: false,
      defaultEncoding: 'utf8',
      awaitDrainWriters: null,
      multiAwaitDrain: false,
      readingMore: false,
      decoder: null,
      encoding: null,
      [Symbol(kPaused)]: false
    },
    _events: [Object: null prototype] {
      end: [Array],
      timeout: [Function: socketOnTimeout],
      data: [Function: bound socketOnData],
      error: [Function: socketOnError],
      close: [Array],
      drain: [Function: bound socketOnDrain],
      resume: [Function: onSocketResume],
      pause: [Function: onSocketPause]
    },
    _eventsCount: 8,
    _maxListeners: undefined,
    _writableState: WritableState {
      objectMode: false,
      highWaterMark: 16384,
      finalCalled: false,
      needDrain: false,
      ending: false,
      ended: false,
      finished: false,
      destroyed: false,
      decodeStrings: false,
      defaultEncoding: 'utf8',
      length: 0,
      writing: false,
      corked: 0,
      sync: true,
      bufferProcessing: false,
      onwrite: [Function: bound onwrite],
      writecb: null,
      writelen: 0,
      afterWriteTickInfo: null,
      buffered: [],
      bufferedIndex: 0,
      allBuffers: true,
      allNoop: true,
      pendingcb: 0,
      prefinished: false,
      errorEmitted: false,
      emitClose: false,
      autoDestroy: false,
      errored: null,
      closed: false,
      closeEmitted: false
    },
    allowHalfOpen: true,
    _sockname: null,
    _pendingData: null,
    _pendingEncoding: '',
    server: Server {
      maxHeaderSize: undefined,
      insecureHTTPParser: undefined,
      _events: [Object: null prototype],
      _eventsCount: 2,
      _maxListeners: undefined,
      _connections: 1,
      _handle: [TCP],
      _usingWorkers: false,
      _workers: [],
      _unref: false,
      allowHalfOpen: true,
      pauseOnConnect: false,
      httpAllowHalfOpen: false,
      timeout: 0,
      keepAliveTimeout: 5000,
      maxHeadersCount: null,
      headersTimeout: 60000,
      requestTimeout: 0,
      _connectionKey: '6::::8089',
      [Symbol(IncomingMessage)]: [Function: IncomingMessage],
      [Symbol(ServerResponse)]: [Function: ServerResponse],
      [Symbol(kCapture)]: false,
      [Symbol(async_id_symbol)]: 12
    },
    _server: Server {
      maxHeaderSize: undefined,
      insecureHTTPParser: undefined,
      _events: [Object: null prototype],
      _eventsCount: 2,
      _maxListeners: undefined,
      _connections: 1,
      _handle: [TCP],
      _usingWorkers: false,
      _workers: [],
      _unref: false,
      allowHalfOpen: true,
      pauseOnConnect: false,
      httpAllowHalfOpen: false,
      timeout: 0,
      keepAliveTimeout: 5000,
      maxHeadersCount: null,
      headersTimeout: 60000,
      requestTimeout: 0,
      _connectionKey: '6::::8089',
      [Symbol(IncomingMessage)]: [Function: IncomingMessage],
      [Symbol(ServerResponse)]: [Function: ServerResponse],
      [Symbol(kCapture)]: false,
      [Symbol(async_id_symbol)]: 12
    },
    parser: HTTPParser {
      '0': [Function: bound setRequestTimeout],
      '1': [Function: parserOnHeaders],
      '2': [Function: parserOnHeadersComplete],
      '3': [Function: parserOnBody],
      '4': [Function: parserOnMessageComplete],
      '5': [Function: bound onParserExecute],
      '6': [Function: bound onParserTimeout],
      _headers: [],
      _url: '',
      socket: [Circular *1],
      incoming: [IncomingMessage],
      outgoing: null,
      maxHeaderPairs: 2000,
      _consumed: true,
      onIncoming: [Function: bound parserOnIncoming],
      [Symbol(resource_symbol)]: [HTTPServerAsyncResource]
    },
    on: [Function: socketListenerWrap],
    addListener: [Function: socketListenerWrap],
    prependListener: [Function: socketListenerWrap],
    _paused: false,
    _httpMessage: [Circular *2],
    [Symbol(async_id_symbol)]: 15351,
    [Symbol(kHandle)]: TCP {
      reading: true,
      onconnection: null,
      _consumed: true,
      [Symbol(owner_symbol)]: [Circular *1]
    },
    [Symbol(kSetNoDelay)]: false,
    [Symbol(lastWriteQueueSize)]: 0,
    [Symbol(timeout)]: null,
    [Symbol(kBuffer)]: null,
    [Symbol(kBufferCb)]: null,
    [Symbol(kBufferGen)]: null,
    [Symbol(kCapture)]: false,
    [Symbol(kBytesRead)]: 0,
    [Symbol(kBytesWritten)]: 0,
    [Symbol(RequestTimeout)]: undefined
  },
  _header: null,
  _keepAliveTimeout: 5000,
  _onPendingData: [Function: bound updateOutgoingData],
  _sent100: false,
  _expect_continue: false,
  req: IncomingMessage {
    _readableState: ReadableState {
      objectMode: false,
      highWaterMark: 16384,
      buffer: BufferList { head: null, tail: null, length: 0 },
      length: 0,
      pipes: [],
      flowing: true,
      ended: true,
      endEmitted: true,
      reading: false,
      sync: true,
      needReadable: false,
      emittedReadable: false,
      readableListening: false,
      resumeScheduled: false,
      errorEmitted: false,
      emitClose: true,
      autoDestroy: false,
      destroyed: false,
      errored: null,
      closed: false,
      closeEmitted: false,
      defaultEncoding: 'utf8',
      awaitDrainWriters: null,
      multiAwaitDrain: false,
      readingMore: true,
      decoder: null,
      encoding: null,
      [Symbol(kPaused)]: false
    },
    _events: [Object: null prototype] { end: [Function: clearRequestTimeout] },
    _eventsCount: 1,
    _maxListeners: undefined,
    socket: <ref *1> Socket {
      connecting: false,
      _hadError: false,
      _parent: null,
      _host: null,
      _readableState: [ReadableState],
      _events: [Object: null prototype],
      _eventsCount: 8,
      _maxListeners: undefined,
      _writableState: [WritableState],
      allowHalfOpen: true,
      _sockname: null,
      _pendingData: null,
      _pendingEncoding: '',
      server: [Server],
      _server: [Server],
      parser: [HTTPParser],
      on: [Function: socketListenerWrap],
      addListener: [Function: socketListenerWrap],
      prependListener: [Function: socketListenerWrap],
      _paused: false,
      _httpMessage: [Circular *2],
      [Symbol(async_id_symbol)]: 15351,
      [Symbol(kHandle)]: [TCP],
      [Symbol(kSetNoDelay)]: false,
      [Symbol(lastWriteQueueSize)]: 0,
      [Symbol(timeout)]: null,
      [Symbol(kBuffer)]: null,
      [Symbol(kBufferCb)]: null,
      [Symbol(kBufferGen)]: null,
      [Symbol(kCapture)]: false,
      [Symbol(kBytesRead)]: 0,
      [Symbol(kBytesWritten)]: 0,
      [Symbol(RequestTimeout)]: undefined
    },
    httpVersionMajor: 1,
    httpVersionMinor: 1,
    httpVersion: '1.1',
    complete: true,
    headers: {
      host: 'localhost:8089',
      connection: 'keep-alive',
      'content-length': '0',
      'cache-control': 'max-age=0',
      'upgrade-insecure-requests': '1',
      origin: 'http://localhost:8089',
      'content-type': 'application/x-www-form-urlencoded',
      'user-agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/88.0.4324.150 Safari/537.36',
      accept: 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9',
      'sec-fetch-site': 'same-origin',
      'sec-fetch-mode': 'navigate',
      'sec-fetch-user': '?1',
      'sec-fetch-dest': 'document',
      referer: 'http://localhost:8089/add_device',
      'accept-encoding': 'gzip, deflate, br',
      'accept-language': 'en-US'
    },
    rawHeaders: [
      'Host',
      'localhost:8089',
      'Connection',
      'keep-alive',
      'Content-Length',
      '0',
      'Cache-Control',
      'max-age=0',
      'Upgrade-Insecure-Requests',
      '1',
      'Origin',
      'http://localhost:8089',
      'Content-Type',
      'application/x-www-form-urlencoded',
      'User-Agent',
      'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/88.0.4324.150 Safari/537.36',
      'Accept',
      'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9',
      'Sec-Fetch-Site',
      'same-origin',
      'Sec-Fetch-Mode',
      'navigate',
      'Sec-Fetch-User',
      '?1',
      'Sec-Fetch-Dest',
      'document',
      'Referer',
      'http://localhost:8089/add_device',
      'Accept-Encoding',
      'gzip, deflate, br',
      'Accept-Language',
      'en-US'
    ],
    trailers: {},
    rawTrailers: [],
    aborted: false,
    upgrade: false,
    url: '/add_device',
    method: 'POST',
    statusCode: null,
    statusMessage: null,
    client: <ref *1> Socket {
      connecting: false,
      _hadError: false,
      _parent: null,
      _host: null,
      _readableState: [ReadableState],
      _events: [Object: null prototype],
      _eventsCount: 8,
      _maxListeners: undefined,
      _writableState: [WritableState],
      allowHalfOpen: true,
      _sockname: null,
      _pendingData: null,
      _pendingEncoding: '',
      server: [Server],
      _server: [Server],
      parser: [HTTPParser],
      on: [Function: socketListenerWrap],
      addListener: [Function: socketListenerWrap],
      prependListener: [Function: socketListenerWrap],
      _paused: false,
      _httpMessage: [Circular *2],
      [Symbol(async_id_symbol)]: 15351,
      [Symbol(kHandle)]: [TCP],
      [Symbol(kSetNoDelay)]: false,
      [Symbol(lastWriteQueueSize)]: 0,
      [Symbol(timeout)]: null,
      [Symbol(kBuffer)]: null,
      [Symbol(kBufferCb)]: null,
      [Symbol(kBufferGen)]: null,
      [Symbol(kCapture)]: false,
      [Symbol(kBytesRead)]: 0,
      [Symbol(kBytesWritten)]: 0,
      [Symbol(RequestTimeout)]: undefined
    },
    _consuming: false,
    _dumped: false,
    next: [Function: next],
    baseUrl: '',
    originalUrl: '/add_device',
    _parsedUrl: Url {
      protocol: null,
      slashes: null,
      auth: null,
      host: null,
      port: null,
      hostname: null,
      hash: null,
      search: null,
      query: null,
      pathname: '/add_device',
      path: '/add_device',
      href: '/add_device',
      _raw: '/add_device'
    },
    params: {},
    query: {},
    res: [Circular *2],
    body: {},
    _body: true,
    length: undefined,
    route: Route { path: '/add_device', stack: [Array], methods: [Object] },
    [Symbol(kCapture)]: false,
    [Symbol(RequestTimeout)]: undefined
  },
  locals: [Object: null prototype] {},
  [Symbol(kCapture)]: false,
  [Symbol(kNeedDrain)]: false,
  [Symbol(corked)]: 0,
  [Symbol(kOutHeaders)]: [Object: null prototype] {
    'x-powered-by': [ 'X-Powered-By', 'Express' ]
  }
}

打印 console.log(req.body.device); 时我想要的是 { device: dviceNameClickedByTheUser } 任何帮助将不胜感激,谢谢!

确保您使用的是 express.urlencoded({ extended: true }) 中间件, 如 documentation 所示,否则 req.body 将是未定义的。

您发布的 console.log(req.body.device) 的输出可能是过时代码 运行 的结果,因为这是您通常从 运行 console.log(req) 获得的结果。 我试过 运行 你的代码,控制台输出正常 https://www.anyfiddle.com/p/robalb/sih511dv

此外,这与问题无关,但您可以通过将表单按钮的类型从 type="text" 更改为 [=16= 来摆脱模板中的 javascript 代码] 像这样

<button name="device" value="<%= deviceType.device %>"
                            type="submit"><%= deviceType.device %></button>

使用隐藏输入标签解决:

<script>
    /* Submit device type form when user clicks on div */
    $(function () {
        $(".device-form").on("click", function () {
            $(this).submit();
        });

    });
</script>

<body>
    <div id="devices-available-container">

        <% deviceTypes.forEach(function(deviceType){ %>
        <div class="device-type-card">
            <form class="device-form" method="POST" action="/add_device">
                <input input type="hidden" id="first" type="text" name="device" value="<%= deviceType.device %>" />
                <div class="icon-and-text-container">
                    <div class="circle"><img class="icon" src="/img/device_types/<%=deviceType.device%>.png"
                            alt="Lightbulb icon"></div>
                    <div class="icon-description">
                        <p><%= deviceType.device %></p>
                    </div>
                </div>
            </form>
        </div>
        <% }) %>

    </div>
</body>