ИМХО, самый технологичный путь - использование Ajax.
Тогда можно сохранять прямо в клиенте идентификатор отправленной формы, скажем, в куках, и предотвращать повторную отправку, проверяя его наличие. Всю валидацию формы можно проходить яваскриптом перед отправкой, что снимет часть нагрузки с сервера и оставит ему лишь проверку каптчи и парсинг полученных данных.
Почему Ajax не всегда возможен? Мобильные броузеры уже все поддерживают ES-5, а его вполне достаточно для Ajax-запроса. Вы не любите jQuery? Вы просто не умеете его готовить (С). На самом деле, я его тоже терпеть не могу. Но вполне несложно написать кроссброузерный объект, полностью реализующий все, что нужно для асинхронки. Если нужно, могу помочь. Просто я использую свою библиотеку, синтаксис которой местами не очень понятен остальным.
Справедливости ради, нужно сказать что 1 путь - это хорошая олдскульная практика. Можно его немного доработать, обнуляя поля формы, и тогда повторная отправка данных будет невозможна.