【问题标题】:Upload file is only sending text to e-mail from React Form上传文件仅从 React Form 向电子邮件发送文本
【发布时间】:2020-10-01 00:17:33
【问题描述】:

所以我正在尝试将从 React 中的表单输入的数据发送到电子邮件地址。

一切正常,除了我尝试上传文件并且它只将路径文件的文本发送到电子邮件。


例如,电子邮件将如下所示:

来自:测试

电子邮件:testing@gmail.com

消息:测试

文件:C:\fakepath\2020-06-10 18-49-37.mp4


我显然不希望文本显示在电子邮件上,而是要上传一个文件。

关于如何完成这项工作的任何想法。

我将在下面发布大量代码供大家查看。

提前致谢!

Form.jsx

import React from 'react'
import Axios from 'axios'


class Form extends React.Component {
  constructor(props) {
    super(props);
    super(props);
    this.state = {
      name: '',
      email: '',
      message: '',
      file: null,
    };
    this.handleChange = this.handleChange.bind(this);
    this.handleSubmit = this.handleSubmit.bind(this);
  }

  handleChange(event) {
    this.setState(
      {
        [event.target.name]: event.target.value,
        [event.target.email]: event.target.value,
        [event.target.message]: event.target.value,
        [event.target.file]: event.target.file,
      }
    );
  }

    this.setState({
      [name]: value
    })

  }

  handleSubmit(event) {
    console.log(this.state)
    event.preventDefault();
    const data = {
      name: this.state.name,
      email: this.state.email,
      message: this.state.message,
      file: this.state.file,
    };

    Axios.post("api/v1/sendMail", data)
      {
      alert("Thank you! We will be in touch shortly!")
      }
  }

  render() {
    return (
      <React.Fragment>
        <div className="formContainer centerImg" id="formScale">
          <form onSubmit={this.handleSubmit} method="post">
            <div className='contact'>
              <h2 className="formTitles">YOUR FULL NAME</h2>
              <input
                name='name'
                value={this.state.name}
                onChange={this.handleChange}
                required />
              <h2 className="formTitles">EMAIL ADDRESS</h2>
              <input
                name='email'
                value={this.state.email}
                onChange={this.handleChange}
                required />
              <h2 className="formTitles">UPLOAD FILE</h2>
              <input
                type='file'
                name='file'
                value={this.state.file}
                onChange={this.handleChange} />
              <div id='messageForm'>
                <h2 className="formTitles">MESSAGE</h2>
                <textarea
                  name='message'
                  value={this.state.message}
                  onChange={this.handleChange}
                  required />
              </div>                      
              <div id='submit-btn'>
                <input type='submit' value='SUBMIT' />
              </div>
            </div>
          </form>
        </div>
      </React.Fragment>
    )
  }
}

export default Form

(服务器)index.js

const server = require('./server')

const bodyParser = require("body-parser");
const cookieParser = require("cookie-parser");

server.use(bodyParser.urlencoded({ extended: true }));
server.use(bodyParser.json());
server.use(cookieParser());

const { sendEmail } = require("../server/routes/mail");

server.post("/api/v1/sendMail", (req, res) => {
  sendEmail(req.body.name, req.body.email, req.body.message, req.body.file);
});

const port = 3000

server.listen(port, () => {
  // eslint-disable-next-line no-console
  console.log('Server listening on port', port)
})

ma​​il.js

const mailer = require("nodemailer");

const getEmailData = (name, email, message, file) => {
    let data = null;


            data = {
                from: "Contact Form",
                to: "(*correct e-mail here*)",
                subject: `Message from the contact form!`,
                html: `<b>From:</b>&nbsp;${name}
                      <br><br><b>Email:</b>&nbsp;${email}
                      <br><br><b>Message:</b>&nbsp;${message}
                      <br><br><b>File:</b>&nbsp;${file}`
            }
    return data;
}


    const sendEmail = (name, email, message, file) => {

        const smtpTransport = mailer.createTransport({
            service: "Gmail",
            auth: {
                user: "(correct e-mail here)",
                pass: "(correct password here)"
            }
        })

        const mail = getEmailData(name, email, message, file)

        smtpTransport.sendMail(mail, function(error, response) {
            if(error) {
                console.log(error)
            } else {
                alert( "Thank you! We will be in touch shortly!")
            }
            smtpTransport.close();
        })


    }

    module.exports = { sendEmail }

【问题讨论】:

    标签: javascript node.js reactjs forms file-upload


    【解决方案1】:

    我建议你发送FormData 并在服务器上解析FormData。

    对于快速服务器,您可以使用multer 来解析请求。

    在客户端发送表单数据:

    const formData = new FormData();
    formData.append("name", this.state.name);
    formData.append("email", this.state.email);
    formData.append("message", this.state.message);
    formData.append("file", this.state.file);
    Axios.post("api/v1/sendMail", formData);
    

    在服务器端,在您的请求处理程序中使用directUpload 中间件和console.log(req.files)

    const upload = multer({
      storage: multer.memoryStorage()
    });
    const directUpload = upload.fields([{
      name: "name"
    }, {
      name: "email"
    }, {
      name: "message"
    }, {
      name: "file"
    }]);
    
    server.post("/api/v1/sendMail", directUpload, (req, res) => {
      console.log(req.files);
      sendEmail(req.body.name, req.body.email, req.body.message, req.body.file);
    });
    

    【讨论】:

    • 有没有办法用我现在编码的方式来做到这一点?我只是一个大三学生,所以我不知道如何将我所做的任何事情转换成 FormData 格式。
    • 谢谢 ardean,这会放在我的邮件或索引服务器文件上吗?
    • 您可以在邮件处理程序之前使用中间件,就像我在答案中所做的那样。
    • 做了它但它不起作用。有了所有这些代码,它就完全一样了。文本,没有文件。
    【解决方案2】:

    您可以发送FormDataconvert file to dataUri and handle it on the backend

    表单数据

    handleSubmit(event) {
      event.preventDefault();
    
      // or you can set ref to form and use new FormData(formRef.current)
      // but then keeping state doesnt make sense at all
      const formData = new FormData();
      for(let [key, value] of Object.entries(this.state)) {
        formData.append(key, value);
      }
    
    
      Axios.post("api/v1/sendMail", formData)
          {
          alert("Thank you! We will be in touch shortly!")
          }
      }
    
    handleFileChange({target: {name, files}}) {
       this.setState(state => ({...state, [name]: files[0]}))
    }
    
     <input
      type='file'
      name='file'
      onChange={this.handleFileChange} />
    

    数据URI

    const toBase64 = file => new Promise((resolve, reject) => {
        const reader = new FileReader();
        reader.readAsDataURL(file);
        reader.onload = () => resolve(reader.result);
        reader.onerror = error => reject(error);
    });
    
     handleSubmit(event) {
        event.preventDefault();
        const data = {...this.state};
    
        Axios.post("api/v1/sendMail", data)
          {
          alert("Thank you! We will be in touch shortly!")
          }
      }
    
    handleFileChange({target: {name, files}}) {
       toBase64(files[0]).then(dataUri => {
         this.setState(state => ({...state, [name]: dataUri}))
       })
    }
    
    <input
      type='file'
      name='file'
      onChange={this.handleFileChange} />
    

    这也可以简化

    handleChange({target: {name, value}}) {
        this.setState(state => ({...state, [name]: value}))
    }
    

    示例

    const { Component, Fragment, createRef } = React;
    
    const toBase64 = file => new Promise((resolve, reject) => {
        const reader = new FileReader();
        reader.readAsDataURL(file);
        reader.onload = () => resolve(reader.result);
        reader.onerror = error => reject(error);
    });
    
    class Form extends Component {
      constructor(props) {
        super(props);
        
        this.state = {
          variant1: {
            name: '',
            email: '',
            message: '',
            file: null,
          },
          variant2: {
            name: '',
            email: '',
            message: '',
            file: null
          }        
        };
        this.handleChange = this.handleChange.bind(this);
        this.handleSubmit1 = this.handleSubmit1.bind(this);
        this.handleSubmit2 = this.handleSubmit2.bind(this);
        this.handleFileChange1 = this.handleFileChange1.bind(this);
        this.handleFileChange2 = this.handleFileChange2.bind(this);
        this.formRef = createRef(null);
      }
      
      handleFileChange1({target: {name, files}}) {
        toBase64(files[0]).then(dataUri => {
          this.setState(state => ({
            ...state,
            variant1: {
              ...state.variant1,
              [name]: dataUri
            }
          }))
        })
      }
      
      handleFileChange2({target: {name, files}}) {
        this.setState(state => ({
          ...state,
          variant2: {
            ...state.variant2,
            [name]: files[0]
          }
        }))
      }
    
      handleChange({target: {name, value}}) {
        this.setState(state => ({
          ...state,
          variant1: {
            ...state.variant1,
            [name]: value
          },
          variant2: {
            ...state.variant2,
            [name]: value
          }
        }))
      }
    
      handleSubmit1(event) {
        const data = {...this.state.variant1}
        console.log('json', data);
      }
      
      handleSubmit2(event) {
        const formData = new FormData();
        for(let [key, value] of Object.entries(this.state.variant2)) {
          formData.append(key, value);
        }
        console.log('form data', [...formData.entries()]);
        
        const formData1 = new FormData(this.formRef.current);
        console.log('formdata ref', [...formData1.entries()]);
      }
    
      render() {
        const { name, email, message } = this.state.variant1;
        
        return (
          <Fragment>
            <div className="formContainer centerImg" id="formScale">
              <form ref={this.formRef} onSubmit={(event) => {event.preventDefault();this.handleSubmit1(event);this.handleSubmit2(event)}} method="post">
                <div className='contact'>
                  <h2 className="formTitles">YOUR FULL NAME</h2>
                  <input
                    name='name'
                    value={name}
                    onChange={this.handleChange}
                    required />
                  <h2 className="formTitles">EMAIL ADDRESS</h2>
                  <input
                    name='email'
                    value={email}
                    onChange={this.handleChange}
                    required />
                  <h2 className="formTitles">UPLOAD FILE</h2>
                  <input
                    type='file'
                    name='file'
                    onChange={(event) => {this.handleFileChange1(event);this.handleFileChange2(event)}} />
                  <div id='messageForm'>
                    <h2 className="formTitles">MESSAGE</h2>
                    <textarea
                      name='message'
                      value={message}
                      onChange={this.handleChange}
                      required />
                  </div>                      
                  <div id='submit-btn'>
                    <input type='submit' value='SUBMIT' />
                  </div>
                </div>
              </form>
            </div>
          </Fragment>
        )
      }
    }
    
    ReactDOM.render(
        <Form />,
        document.getElementById('root')
      );
    <script src="https://unpkg.com/react/umd/react.development.js"></script>
    <script src="https://unpkg.com/react-dom/umd/react-dom.development.js"></script>
    <script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
    <div id="root"></div>

    【讨论】:

    • 更新了答案。这里有两个解决方案
    • 复制了代码,没有用。这一切都是未定义的。
    • 您选择了哪种解决方案?你绑定handleFileChange了吗? console log(this.state)console log([...formData.entries()]) 显示什么?
    • 我都试过了,都不管用。它要么只是再次以文本形式出现路径文件,要么以未定义的形式出现。我也绑定了handleFileChange。控制台日志显示未定义或仅显示从表单输入的文本。
    • 所以我设法让它工作。我使用了所有 Data Uri 示例,必须将限制设置为 50mb,尽管我必须将文件作为带有 nodemailer 语法的附件放在我的 mail.js 文件中,如下所示:附件:[{path:${file}},感谢您的帮助:)
    【解决方案3】:

    Józef Podlecki 提供了获得正确解决方案的指导,这是任何试图让最终解决方案发挥作用的人的最终代码。

    Form.jsx

    import React from 'react'
    import Axios from 'axios'
    
    const toBase64 = file => new Promise((resolve, reject) => {
      const reader = new FileReader();
      reader.readAsDataURL(file);
      reader.onload = () => resolve(reader.result);
      reader.onerror = error => reject(error);
    });
    
    class Form extends React.Component {
      constructor(props) {
        super(props);
        this.state = {
          name: '',
          email: '',
          message: '',
          file: null,
    
        };
        this.handleChange = this.handleChange.bind(this);
        this.handleSubmit = this.handleSubmit.bind(this);
        this.handleFileChange = this.handleFileChange.bind(this);
      }
    
      handleFileChange({target: {name, files}}) {
        toBase64(files[0]).then(dataUri => {
          this.setState(state => ({...state, [name]: dataUri}))
        })
     }
    
      handleChange(event) {
        this.setState(
          {
            [event.target.name]: event.target.value,
            [event.target.email]: event.target.value,
            [event.target.message]: event.target.value,
          }
        );
      }
    
      handleSubmit(event) {
        event.preventDefault();
        const data = {...this.state};
    
        Axios.post("api/v1/sendMail", data)
          {
          alert("Thank you! We will be in touch shortly!")
          }
      }
    
      render() {
        return (
          <React.Fragment>
            <div className="formContainer centerImg" id="formScale">
              <form onSubmit={this.handleSubmit} method="post">
                <div className='contact'>
                  <h2 className="formTitles">YOUR FULL NAME</h2>
                  <input
                    name='name'
                    value={this.state.name}
                    onChange={this.handleChange}
                    required />
                  <h2 className="formTitles">EMAIL ADDRESS</h2>
                  <input
                    name='email'
                    value={this.state.email}
                    onChange={this.handleChange}
                    required />
                  <h2 className="formTitles">UPLOAD FILE</h2>
                  <input
                    type='file'
                    name='file'
                    // value={this.state.file}
                    onChange={this.handleFileChange} />
                  <div id='messageForm'>
                    <h2 className="formTitles">MESSAGE</h2>
                    <textarea
                      name='message'
                      value={this.state.message}
                      onChange={this.handleChange}
                      required />
                  </div>
                  <div id='submit-btn'>
                    <input type='submit' value='SUBMIT' />
                  </div>
                </div>
              </form>
            </div>
          </React.Fragment>
        )
      }
    }
    
    export default Form
    

    (服务器)index.js

    const server = require('./server')
    const express = require('express')
    
    const bodyParser = require("body-parser");
    const cookieParser = require("cookie-parser");
    
    server.use(express.json({limit: '50mb'}))
    server.use(bodyParser.urlencoded({ extended: true }));
    server.use(bodyParser.json());
    server.use(cookieParser());
    
    const { sendEmail } = require("../server/routes/mail");
    
    
    
    server.post("/api/v1/sendMail", (req, res) => {
      sendEmail(req.body.name, req.body.email, req.body.message, req.body.file);
    });
    
    const port = process.env.PORT || 3000;
    
    server.listen(port, () => {
      // eslint-disable-next-line no-console
      console.log('Server listening on port', port)
    })
    

    ma​​il.js

    const mailer = require("nodemailer");
    
    const getEmailData = (name, email, message, file) => {
        let data = null;
    
    
            data = {
                from: "Contact Form",
                to: "(correct e-mail here)",
                subject: `Message from the contact form!`,
                attachments: [
                    {
                      path: `${file}`
                    }
                  ],
                html: `<b>From:</b>&nbsp;${name}
                      <br><br><b>Email:</b>&nbsp;${email}
                      <br><br><b>Message:</b>&nbsp;${message}`
                }
        return data;
    }
    
    
        const sendEmail = (name, email, message, file) => {
    
            const smtpTransport = mailer.createTransport({
                service: "Gmail",
                auth: {
                    user: "(correct e-mail here)",
                    pass: "(correct password here)"
                }
            })
    
            const mail = getEmailData(name, email, message, file)
    
            smtpTransport.sendMail(mail, function(error, response) {
                if(error) {
                    console.log(error)
                } else {
                    alert( "Thank you! We will be in touch shortly!")
                }
                smtpTransport.close();
            })
    
    
        }
    
        module.exports = { sendEmail }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-04-12
      • 1970-01-01
      • 2019-07-26
      • 2021-09-14
      • 2017-01-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多