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

Gatsby生产构建后AJAX表单请求失效,提交自动跳转求助

解决Gatsby生产环境下Formspree表单AJAX提交失效、自动跳转的问题

我帮你排查了几个核心问题点,结合你的代码给出针对性的修复方案:

1. 表单提交事件绑定逻辑错误(最关键原因)

你现在是给提交按钮绑定click事件,但表单的触发场景不止点击按钮(比如用户在输入框按回车提交),更重要的是在Gatsby生产构建的hydration(水化)过程中,按钮的click事件绑定可能存在延迟或失效,导致event.preventDefault()没被正确执行,最终触发表单的默认跳转行为。

修复方案:改为监听表单的submit事件,这样能覆盖所有提交场景,且阻止默认行为的逻辑更可靠:

if (typeof window !== `undefined`) {
  document.addEventListener('DOMContentLoaded',function(){
    var contactForm = document.querySelector('#myform'),
        inputName = contactForm.querySelector('[name="name"]'),
        inputEmail = contactForm.querySelector('[name="email"]'),
        inputMessage = contactForm.querySelector('[name="message"]'),
        sendButton = contactForm.querySelector('#send-button');

    // 替换为监听表单的submit事件
    contactForm.addEventListener('submit', function(event){
      event.preventDefault(); // 彻底阻止表单默认提交跳转
      sendButton.value = 'Sending..';

      var xhr = new XMLHttpRequest();
      // 改成HTTPS协议,避免生产环境混合内容被浏览器拦截
      xhr.open('POST', 'https://formspree.io/testmail@gmail.com', true);
      xhr.setRequestHeader("Accept", "application/json");
      xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");

      xhr.onloadend = function (res) {
        if (res.target.status === 200){
          sendButton.value = 'Message sent! I will be in touch soon.';
          contactForm.reset();
        } else {
          sendButton.value = 'Error!';
        }
      }

      // 修复参数格式:添加&分隔符,并用encodeURIComponent处理特殊字符
      var formData = "name=" + encodeURIComponent(inputName.value) 
                   + "&email=" + encodeURIComponent(inputEmail.value) 
                   + "&message=" + encodeURIComponent(inputMessage.value);
      xhr.send(formData);
    });
  });
}

2. AJAX请求参数格式错误

你的原始代码里,xhr.send()的参数没有用&分隔,会导致所有参数被合并成一串无效内容(比如name=张三email=xxx@xx.commessage=xxx),Formspree无法解析这些参数,请求失败后就会触发表单的默认跳转。同时没有对输入值做编码处理,遇到空格、@、&等特殊字符也会导致请求异常。

上面的修复代码已经解决了这个问题:添加了&分隔符,并通过encodeURIComponent对用户输入做了编码。

3. 混合内容协议不兼容

你的表单action和AJAX请求用的是http://formspree.io,如果生产站点部署在HTTPS环境下,浏览器会阻止HTTP的AJAX请求(混合内容安全限制),导致请求失败,最终触发表单默认跳转。

修复方案:把请求地址改成https://formspree.io/testmail@gmail.com,和站点协议保持一致。

额外优化建议(如果是React组件场景)

如果你的表单是在React组件中实现,更推荐用React的状态管理和useEffect来绑定事件,避免原生DOM操作的兼容性问题:

import { useEffect, useRef } from 'react';

const ContactForm = () => {
  const formRef = useRef(null);
  const sendButtonRef = useRef(null);

  useEffect(() => {
    const contactForm = formRef.current;
    const sendButton = sendButtonRef.current;

    const handleSubmit = (e) => {
      e.preventDefault();
      sendButton.value = 'Sending..';

      const inputName = contactForm.querySelector('[name="name"]');
      const inputEmail = contactForm.querySelector('[name="email"]');
      const inputMessage = contactForm.querySelector('[name="message"]');

      const xhr = new XMLHttpRequest();
      xhr.open('POST', 'https://formspree.io/testmail@gmail.com', true);
      xhr.setRequestHeader("Accept", "application/json");
      xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");

      xhr.onloadend = (res) => {
        if (res.target.status === 200){
          sendButton.value = 'Message sent! I will be in touch soon.';
          contactForm.reset();
        } else {
          sendButton.value = 'Error!';
        }
      }

      const formData = "name=" + encodeURIComponent(inputName.value) 
                   + "&email=" + encodeURIComponent(inputEmail.value) 
                   + "&message=" + encodeURIComponent(inputMessage.value);
      xhr.send(formData);
    };

    contactForm.addEventListener('submit', handleSubmit);
    // 组件卸载时移除事件监听,避免内存泄漏
    return () => contactForm.removeEventListener('submit', handleSubmit);
  }, []);

  return (
    <form ref={formRef} id='myform' action="https://formspree.io/testmail@gmail.com" method="POST">
      <div className="formgroup">
        <input id='name' type="text" name="name" placeholder='Name'/>
        <input id='email' type="email" name="email" placeholder='Email'/>
      </div>
      <div className="formfield">
        <textarea id='message' name="message" rows='6' placeholder='Message'/>
      </div>
      <div className="formfield">
        <input ref={sendButtonRef} id='send-button' type="submit" value="Send"/>
      </div>
    </form>
  );
};

export default ContactForm;

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 04:47:06