联系表单发送按钮无法提交,请求技术排查
问题描述
正在开发网站联系表单,用户输入姓名、邮箱与留言后,信息需通过SendGrid API发送至办公邮箱。服务端代码实现于server.js,但点击发送按钮无任何反应。已确认server.js运行正常、SendGrid API密钥有效,表单已绑定onSubmit={submitHandler}。
服务端代码(server.js)
// server.js const express = require("express"); const sgMail = require("@sendgrid/mail"); const { resolve } = require("path-browserify"); // Set up SendGrid API key sgMail.setApiKey("***********"); // Create Express app const app = express(); // Middleware to parse JSON requests app.use(express.json()); app.get("/", (req, res) => { res.send("Hello, server!"); }); // Route to handle sending emails app.post("/send-email", (req, res) => { const { Name, Email, Message, submitbutton } = req.body; const msg = { to: "******@gmail.com", from: "******@gmail.com", subject: "Example Subject", text: `Name: ${Name}\nEmail: ${Email}\nMessage: ${Message}\nSubmit Button: ${submitbutton}`, html: `<p>Name: ${Name}</p><p>Email: ${Email}</p><p>Message: ${Message}</p><p>Submit Button: ${submitbutton}</p>`, }; sgMail .send(msg) .then(() => { res.status(200).json({ message: "Email sent successfully" }); }) .catch((error) => { console.error(error.toString()); res.status(500).json({ error: "Failed to send email" }); }); }); // Set up fallback for path module resolve.fallback = { path: require.resolve("path-browserify") }; // Start the server app.listen(4000, () => { console.log("Server started on port 3000"); });
客户端代码(card.tsx)
import React, { useState, useEffect, useRef } from "react"; import cardcss from "./Card.module.css"; import axios from "axios"; interface CardProps { imageUrl: string; title: string; body: string; } function Card(props: CardProps) { const [message, setMessage] = useState(""); const nameInputRef = useRef<HTMLInputElement>(null); const emailInputRef = useRef<HTMLInputElement>(null); const messageInputRef = useRef<HTMLInputElement>(null); useEffect(() => { if (messageInputRef.current) { messageInputRef.current.focus(); messageInputRef.current.setSelectionRange(0, 0); // Delay setting the cursor position setTimeout(() => { messageInputRef.current?.setSelectionRange(0, 0); }, 0); } }, []); const handleFocus = (event: React.FocusEvent<HTMLInputElement>) => { event.target.setSelectionRange(0, 0); }; const submitHandler = (event: React.FormEvent<HTMLFormElement>) => { event.preventDefault(); if ( nameInputRef.current && emailInputRef.current && messageInputRef.current ) { const nameInput = nameInputRef.current.value; const emailInput = emailInputRef.current.value; const messageInput = messageInputRef.current.value; const contactData = { Name: nameInput, Email: emailInput, Message: messageInput, }; axios .post("/send-email", contactData) .then((response) => { console.log(response.data); // Handle success response }) .catch((error) => { console.error(error); // Handle error response }); } }; return ( // JSX code for the contact form // ... ); } export default Card;
排查与解决建议
1. 服务端端口不一致问题
server.js中app.listen(4000)但日志输出Server started on port 3000,会导致你误以为服务运行在3000端口,实际是4000端口,客户端请求可能指向错误端口。
- 修复:统一端口号,比如把
app.listen(4000)改为app.listen(3000),或者修改日志为console.log("Server started on port 4000")。
2. 错误的resolve.fallback配置
代码中resolve.fallback = { path: require.resolve("path-browserify") }是Webpack的配置项,不是Express的API,放在server.js中会抛出TypeError: Cannot set properties of function (setting 'fallback')错误,导致服务无法正常启动。
- 修复:直接删除这行代码,
path-browserify在Node.js环境中不需要额外配置,Express也不需要这个fallback设置。
3. 客户端请求跨域/地址错误
如果React客户端运行在默认的3000端口,而服务端在4000端口,axios.post("/send-email")会请求客户端所在的3000端口,导致跨域问题,请求无法到达服务端。
- 修复方案二选一:
- 在React项目的
package.json中添加"proxy": "http://localhost:4000"(开发环境有效),axios会自动转发请求到服务端端口。 - 直接写全请求地址:
axios.post("http://localhost:4000/send-email", contactData)。
- 在React项目的
4. 表单元素与Ref类型不匹配
messageInputRef被定义为HTMLInputElement,但如果表单中留言框是<textarea>元素,ref.current会是null,导致submitHandler中的if条件不满足,代码不会执行发送请求的逻辑。
- 修复:如果留言框是textarea,修改Ref类型为
HTMLTextAreaElement:
同时确保JSX中的表单元素正确绑定ref:const messageInputRef = useRef<HTMLTextAreaElement>(null);<input type="text" ref={nameInputRef} /> <input type="email" ref={emailInputRef} /> <textarea ref={messageInputRef} />
5. 额外优化:添加错误日志
如果submitHandler中的if条件不满足,添加日志提示方便排查:
const submitHandler = (event: React.FormEvent<HTMLFormElement>) => { event.preventDefault(); if ( nameInputRef.current && emailInputRef.current && messageInputRef.current ) { // 发送请求逻辑 } else { console.error("表单元素Ref未正确绑定"); } };
内容的提问来源于stack exchange,提问作者user22081405

