2

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

2 Answers 2

1

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 ¯_(ツ)_/¯

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.

3
  • Unfortunately this hasn’t done the trick, yet. Now I get a 400 Bad Request. These are the headers: 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? Jul 27, 2018 at 8:11
  • Probably just need to pass CSRF data in? craftcms.com/support/csrf-protection#updating-your-javascript (Craft 3 syntax: craftcms.stackexchange.com/a/26726/57)
    – Brad Bell
    Jul 27, 2018 at 14:03
  • 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 (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). Jul 27, 2018 at 15:03

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.