воскресенье, 20 октября 2013 г.

Отправка формы с method="get" методом post

Зачастую по многим причинам методом отправки запросов на сервер мы выбираем GET. Но бывают случаи, когда необходимо сделать исключение и данный запрос отправить через POST. Этот небольшой how-to о том, как подменить методы при отправке запросов. Коснёмся так же добавления токена CSRF.
Наиболее очевидный способ - использовать jQuery.post, который просто оборачивает jQuery.ajax. Но как быть, если мы в данном случае не можем использовать ajax или это заставляет делать нас ненужные телодвижения? Ответ не менее очевидный - использовать нативный POST, без ajax. Для этого нам потребуется в javascript создать новую форму с method="POST" и просто отправить её. Сначала приведён весь код, рассмотрим его подробно ниже.
var CSRF_TOKEN = document.getElementById('csrf_token').value;
var action = window.location.pathname;
var params = query_string.split('&');
var form = $(document.createElement('form')).attr('name', 'csrf_form').attr('action', action).attr('method','post');
$(document.createElement('input')).attr('name', 'csrfmiddlewaretoken').attr('value', CSRF_TOKEN).appendTo(form);
$('body').append(form);
for (var i in params) {
    var tmp = params[i].split('=');
    var key = tmp[0], value = tmp[1];
    $(document.createElement('input')).attr('type', 'hidden').attr('name', key).attr('value', value).appendTo(form);
}
form.submit();
Создаём новую форму через createElement.
var action = "window.location.pathname";
var form = $(document.createElement('form')).attr('action', action).attr('method','post');
$('body').append(form);
form.submit();
Так можно отправить пустую форму. Добавим в неё наши данные. У меня они уже сформированы в строку query_string для отправки методом GET. Разобьём её на ключи и значения и добавим каждую пару в input, дочерний форме.
var params = query_string.split('&');
for (var i in params) {
    var tmp = params[i].split('=');
    var key = tmp[0], value = tmp[1];
    $(document.createElement('input')).attr('type', 'hidden').attr('name', key).attr('value', value).appendTo(form);
}
На этом можно закончить, если у вас не используется защита от межсайтовых запросов через CSRF. Если же используется, придётся костыльнуть. Чтобы скрипт получил CSRF-токен от сервера, нужно добавить его в шаблон страницы. Обычно это делается в форме. Я пользуюсь django, у меня это выглядит так:
<form name="csrf_form" method="post">
    {#form to transfer csrf to javascript#}
    <input type="hidden" id="csrf_token" name="csrfmiddlewaretoken" value="{{ csrf_token }}"/>
</form>
Ключевые атрибуты тут name и value, без них никак.
Получим токен в js и внедрим его в форму. Получается, что мы подменяем изначальную форму с её токеном нашей новой формой, используя старый токен.
var CSRF_TOKEN = document.getElementById('csrf_token').value;
//code
$(document.createElement('input')).attr('name', 'csrfmiddlewaretoken').attr('value', CSRF_TOKEN).appendTo(form);