<p>Solved it (finally).</p>

<p>First part of the problem (the 302 redirect) was this missing configuration in the ajax call:</p>

<pre class="lang-js prettyprint-override"><code>$.post({
  // ...
  dataType: 'json',
  // ...
};
</code></pre>

<p>It tells the server what you expect to get back from it.</p>

<p>Now this was fine, but I ran into a second issue. The xhr request stalled in Safari. When that happend and I reloaded the page (causing the request to finally stop), the email was sent anyways. The reason:</p>

<p>Safari seems to have an issue with this:</p>

<pre class="lang-js prettyprint-override"><code>const formData = new FormData(formElement);
</code></pre>

<p>I found a hint here <a href="https://stackoverflow.com/a/8797289/2342963">https://stackoverflow.com/a/8797289/2342963</a> that fixes the issue: appending the data manually to the <code>FormData</code> instance instead of passing the form element to the constructor.</p>

<p>So this is the working code:</p>

<pre class="lang-js prettyprint-override"><code>const formData = new FormData();

$.each($('input, textarea, select'), function(i, element) {
    if (element.files) {
      $.each(element.files, function(i, file) {
        formData.append(element.name, file);
      });
    } else {
      formData.append(element.name, element.value);
    }
});

$.post({
    url: '/',
    data: formData,
    type: 'POST',
    cache: false,
    contentType: false,
    processData: false,
    dataType: 'json',

    success: response =&gt; {
        if (response.success) {
        // Show success
        } else {
        // Show error
        }
    },
    error: () =&gt; {
        // Show error
    }
});
</code></pre>

<p>Turns out, it wasn’t a Craft issue after all ¯_(ツ)_/¯</p>

CC BY-SA 4.0
2018-08-04T13:19:24.300Z
2018-08-04T13:19:24.300Z
medoingthings
<p>My guess would be this check is failing: <a href="https://github.com/craftcms/contact-form/blob/v2/src/controllers/SendController.php#L60-L62" rel="nofollow noreferrer">https://github.com/craftcms/contact-form/blob/v2/src/controllers/SendController.php#L60-L62</a></p>

<pre><code>if ($request-&gt;getAcceptsJson()) {
    return $this-&gt;asJson(['errors' =&gt; $submission-&gt;getErrors()]);
}
</code></pre>

<p>So it falls through to this redirect because Craft thinks it's a non-AJAX POST: <a href="https://github.com/craftcms/contact-form/blob/v2/src/controllers/SendController.php#L77" rel="nofollow noreferrer">https://github.com/craftcms/contact-form/blob/v2/src/controllers/SendController.php#L77</a></p>

<p>Setting your <code>contentType</code> to <code>application/json</code> instead of <code>false</code> should resolve it.</p>

CC BY-SA 4.0
2018-07-27T08:11:33.497Z
Unfortunately this hasn’t done the trick, yet. Now I get a `400 Bad Request`. These are the headers: https://ibb.co/fS3R68. The response says `<pre>Bad Request: Es ist nicht möglich, Ihre Dateneingabe zu prüfen.</pre>` (It’s not possible to verify your data input). Any ideas?
medoingthings
CC BY-SA 4.0
2018-07-27T14:03:53.823Z
Probably just need to pass CSRF data in? https://craftcms.com/support/csrf-protection#updating-your-javascript (Craft 3 syntax: https://craftcms.stackexchange.com/a/26726/57)
Brad Bell
CC BY-SA 4.0
2018-07-27T15:03:55.310Z
I figured out that when I add `dataType: 'json'` to the jQuery.post call, the `302` error goes away. But I still need to set contentType: false. The csrf token is already part of the request (https://ibb.co/cmLw68) – even if I disabled csrf, it wouldn’t work. With `contentType: false` the form works in Chrome, but for some reason not in Safari. It looks like Safari doesn’t get a response and is pending the whole time. In both cases (with contentType set and without).
medoingthings
CC BY-SA 4.0
2018-07-26T18:03:54.547Z
2018-07-26T18:03:54.547Z
Brad Bell
<p>I’m using the Contact Form plugin to submit a form that can also upload files via Ajax. The problem ist that instead of a success (<code>200</code>) I get a status code of <code>302</code>. But I receive the resulting mail properly.</p>

<p>Everything worked fine when I hadn’t set everything up for the file upload. I serialized the form data, expected json, success (<code>200</code>).</p>

<pre><code>...
dataType: 'json',
data: $(this).serialize(),
...
</code></pre>

<p>But when I switched to this to enable receiving files, things went south (<code>302</code>):</p>

<pre><code>const formData = new FormData(this.form);

$.post({
    url: '/index.php',
    data: formData,
    type: 'POST',
    cache: false,
    contentType: false,
    processData: false,

    success: response =&gt; {
        if (response.success) {
            this.showSuccess();
        } else {
            this.showError();
        }
    },
    error: (xhr) =&gt; {
        // FIXME: This is a workaround because for some reason Craft returns a 302, even though everything works
        //        fine. See stackoverflow question here and fix if there is a solution.
        if (xhr.status === 302) {
        this.showSuccess();
        } else {
        this.showError();
        }
    }
});
</code></pre>

<p>I’m on Craft 3.0.15 and set up SMTP in Settings -> EMail. I tried it locally (using MAMP) and on my hosted server. Both give me the <code>302</code>.</p>

<p>Any hint would be much appreciated. </p>

<p>Cheers,
Mark</p>

<craft3><plugin-contactform>
Contact Form sent via Ajax with file upload returns 302 instead of 200 status code
# Contact Form sent via Ajax with file upload returns 302 instead of 200 status code

(Asked by: username_0 on 2018-07-26)

I’m using the Contact Form plugin to submit a form that can also upload files via Ajax. The problem ist that instead of a success (200) I get a status code of 302. But I receive the resulting mail properly.
Everything worked fine when I hadn’t set everything up for the file upload. I serialized the form data, expected json, success (200).
...
dataType: 'json',
data: $(this).serialize(),
...

But when I switched to this to enable receiving files, things went south (302):
const formData = new FormData(this.form);

$.post({
    url: '/index.php',
    data: formData,
    type: 'POST',
    cache: false,
    contentType: false,
    processData: false,

    success: response => {
        if (response.success) {
            this.showSuccess();
        } else {
            this.showError();
        }
    },
    error: (xhr) => {
        // FIXME: This is a workaround because for some reason Craft returns a 302, even though everything works
        //        fine. See stackoverflow question here and fix if there is a solution.
        if (xhr.status === 302) {
        this.showSuccess();
        } else {
        this.showError();
        }
    }
});

I’m on Craft 3.0.15 and set up SMTP in Settings -> EMail. I tried it locally (using MAMP) and on my hosted server. Both give me the 302.
Any hint would be much appreciated. 
Cheers,
Mark

**Tags:** craft3, plugin-contactform


---

## 2 answers

### Answer by username_0 on 2018-08-04. Score: 1 | Accepted answer

Solved it (finally).
First part of the problem (the 302 redirect) was this missing configuration in the ajax call:
$.post({
  // ...
  dataType: 'json',
  // ...
};

It tells the server what you expect to get back from it.
Now this was fine, but I ran into a second issue. The xhr request stalled in Safari. When that happend and I reloaded the page (causing the request to finally stop), the email was sent anyways. The reason:
Safari seems to have an issue with this:
const formData = new FormData(formElement);

I found a hint here https://stackoverflow.com/a/8797289/2342963 that fixes the issue: appending the data manually to the FormData instance instead of passing the form element to the constructor.
So this is the working code:
const formData = new FormData();

$.each($('input, textarea, select'), function(i, element) {
    if (element.files) {
      $.each(element.files, function(i, file) {
        formData.append(element.name, file);
      });
    } else {
      formData.append(element.name, element.value);
    }
});

$.post({
    url: '/',
    data: formData,
    type: 'POST',
    cache: false,
    contentType: false,
    processData: false,
    dataType: 'json',

    success: response => {
        if (response.success) {
        // Show success
        } else {
        // Show error
        }
    },
    error: () => {
        // Show error
    }
});

Turns out, it wasn’t a Craft issue after all ¯_(ツ)_/¯


---

### Answer by username_1 on 2018-07-26. Score: 0

My guess would be this check is failing: https://github.com/craftcms/contact-form/blob/v2/src/controllers/SendController.php#L60-L62
if ($request->getAcceptsJson()) {
    return $this->asJson(['errors' => $submission->getErrors()]);
}

So it falls through to this redirect because Craft thinks it's a non-AJAX POST: https://github.com/craftcms/contact-form/blob/v2/src/controllers/SendController.php#L77
Setting your contentType to application/json instead of false should resolve it.

> **Comments:**
> **username_0**: Unfortunately this hasn’t done the trick, yet. Now I get a `400 Bad Request`. These are the headers: https://ibb.co/fS3R68. The response says `<pre>Bad Request: Es ist nicht möglich, Ihre Dateneingabe zu prüfen.</pre>` (It’s not possible to verify your data input). Any ideas?  
> **username_1**: Probably just need to pass CSRF data in? https://craftcms.com/support/csrf-protection#updating-your-javascript (Craft 3 syntax: https://craftcms.stackexchange.com/a/26726/57)  
> **username_0**: I figured out that when I add `dataType: 'json'` to the jQuery.post call, the `302` error goes away. But I still need to set contentType: false. The csrf token is already part of the request (https://ibb.co/cmLw68) – even if I disabled csrf, it wouldn’t work. With `contentType: false` the form works in Chrome, but for some reason not in Safari. It looks like Safari doesn’t get a response and is pending the whole time. In both cases (with contentType set and without).  

---

