Вихід: GET або POST?


434

Це питання не в тому, коли використовувати GET або POST взагалі; мова йде про те, що є рекомендованим для обробки виходу з веб-програми. Я знайшов багато інформації про відмінності між GET та POST у загальному розумінні, але я не знайшов однозначної відповіді для цього конкретного сценарію.

Як прагматик, я схильний використовувати GET, тому що реалізувати його набагато простіше, ніж POST; просто опустіть просте посилання і все закінчено. Це, мабуть, має місце у переважній більшості веб-сайтів, про які я можу придумати, принаймні з верху голови. Навіть переповнення стека обробляє вихід із GET.

Те, що змушує мене вагатися, - це (хоч і старий) аргумент, що деякі веб-прискорювачі / проксі-сервери попередньо кешують сторінки, переходячи та завантажуючи кожне посилання, яке вони знаходять на сторінці, тому користувач отримує швидшу відповідь, коли вона натискає на них. Я не впевнений, чи все-таки це стосується, але якби це було так, то теоретично користувача з одним із цих прискорювачів вигнали б із програми, як тільки вона ввійде в систему, тому що її прискорювач знайде та вийде з системи виходу посилання, навіть якщо вона ніколи не натискала на неї.

Все, що я читав до цього часу, говорить про те, що POST слід використовувати для "руйнівних дій", тоді як дії, які не змінюють внутрішній стан запиту, подібного до додатків, і таке - слід обробляти з GET . Виходячи з цього, справжнє питання тут:

Чи вважається вихід із програми деструктивним чи змінює внутрішній стан програми?


Ну, якщо припустити, що ви відвідуєте сайт вперше, а посилання для виходу немає, ви б вийшли з системи, коли ви входите в систему. Було б добре після входу вдруге, оскільки URL виходу вже кешований. Але можна припустити, що будь-який гідний прискорювач зможе відфільтрувати більшість URL-адрес виходу.
HyperCas

2
HyperCas, прискорювачі фільтрації URL-адрес виходу - це теорія, яку я розглядав, і одна з причин, що я вирішив поставити питання. Я відчуваю трохи небажання просто довіряти логіці акселератора, і одного дня користувач із хитрим прискорювачем скаржиться, що вона не може увійти. Чи знаєте ви, чи дотримуються вони стандарт, чи такий стандарт існує?
Даніель Люцці

Будь-який прискорювач, який автоматично подав форму (наприклад), був би шкідливим програмним забезпеченням IMO ... абсолютно нелогічно думати, що прискорювач автоматично подасть форму. Уявіть, що ви відвідуєте Google. Як він міг подати форму пошуку? Ніхто не може рахувати зловмисне програмне забезпечення, оскільки воно занадто непередбачуване і не дотримується правил.
Олексій

3
@AlexW - Я думаю, ти неправильно зрозумів моє запитання. Сценарій акселератора, який я запропонував, полягає в тому, щоб показати можливу проблему при використанні GET, а не POST, тому не було б форми для публікації, лише прості посилання, прискорювачі яких не матимуть жодних проблем.
Даніель Люцці

1
Я усвідомлюю, що я запізнився на це, але Алекс, про це не питає Даніель. Він говорить, що якщо користувач натискає посилання на вихід, а прискорювач повертає кешовану сторінку виходу, не потрапляючи на додаток, то користувач залишатиметься ввійти. Нічого спільного зі зловмисним програмним забезпеченням, хоча FYI, що перевіряє рядок User-Agent, не виправить все одно.
Роб Грант

Відповіді:


475

Використовуйте POST.

У 2010 році використання, GETмабуть, прийнятної відповіді. Але сьогодні (у 2013 році) браузери заздалегідь зароблять сторінки, які вони "думають", що ви відвідаєте наступне.

Ось один із розробників StackOverflow, який розповідає про цю проблему на Twitter:

Хочу подякувати своєму банку за те, що він вийшов із запиту GET, та команді Chrome за зручне попереднє завантаження URL-адрес. Нік Крейвер ( @Nick_Craver ) 29 січня 2013 року

цікавий факт: StackOverflow використовується для обробки виходу через GET, але вже не.


2
Дякую за це оновлення, Дейв. Я навіть не помітив, що SO переключила їх вихід на POST, і я, чесно кажучи, не мав поняття, Chrome має вбудований попередній вибір. Нарешті, твіт, який ви цитували, ніколи не міг запропонувати кращого прикладу проблеми, яку я описав у своєму моє запитання і підтверджує мої підозри. Я голосую за вашу відповідь і роблю її прийнятою.
Даніель Люцці

4
У моєму браузері вихід із системи Stackoverflow виглядає як <li> <a href="https://stackoverflow.com/users/logout"> вийти </a> </li>, що є GET, а не POST
boatcoder

9
@ Mark0978, натисніть посилання.
Девід Мердок

2
Цікаво. Це, мабуть, одна з моїх найменш улюблених функцій - вихід із системи, який потім запитує мене, чи я впевнений. Здогадується, це запобігає попередньому вибору, коли ви виходите з системи, але Amazon, Ebay та Gmail використовують GET для виходу без такої сторінки фокусу між тим, що повідомляється користувачеві, - вихід та фактична подія виходу. Я думаю, що між сторінками це призведе до того, що багато людей помилково вірять, що вони вийшли з системи. Проблеми з цим на SO мінімальні, гроші не беруть участь, і 99% все-таки є загальнодоступним.
човенкодер

7
@Red Відповідно до стандарту HTTP / 1.1, це помилка сервера, а не браузера. Очікується, що GET не матиме побічних ефектів на стороні сервера. Стандарт навіть говорить, що "користувач не вимагав побічних ефектів, тому не може нести за них відповідальність".
eyuelt

45

У REST не повинно бути сеансу, тому руйнувати немає чого. Клієнт REST аутентифікується на кожен запит. Увійшов або вийшов, це просто ілюзія.

Що ви насправді запитуєте, чи повинен браузер продовжувати надсилати інформацію про автентифікацію на кожен запит.

Імовірно, якщо ваша програма створює ілюзію входу в систему, ви повинні мати можливість "вийти" за допомогою JavaScript. Жодна поїздка не потрібна.


Польова дисертація - Розділ 5.1.3

кожен запит від клієнта до сервера повинен містити всю інформацію, необхідну для розуміння запиту, і не може скористатися будь-яким збереженим контекстом на сервері. Тому стан сесії повністю зберігається на клієнті


1
Я насправді цього не знав. Тоді я думаю, що моя програма взагалі не буде дуже ВІДБУДОВОЮ, оскільки я використовую ASP.NET MVC з FormsAuthentication, і вона покладається на сеанси ...
Daniel Liuzzi

19
але на практиці інформація про вхід зберігається у файлі cookie, позначеному httponlyатрибутом, щоб запобігти деяким ризикам xss, а значить, її можна скинути лише з сервера (окрім ручного очищення файлу cookie)
Remus Rusanu

6
"Вручну", як і користувач, переходить до налаштувань браузера і вибирає опцію "Очистити файли cookie". Навряд чи прийнятний спосіб "вийти" з веб-сайту.
Рем Русану

1
@ Remus Ahhh, наскільки відомий веб-браузер робить настільки болючим написання веб-додатків.
Даррел Міллер

1
@DarrelMiller так, але не скасовувати JWT на стороні сервера - це вразливість безпеки. Навіть якщо маркери не зберігаються на сервері, вони повинні бути занесені до чорного списку, коли користувач виходить із системи / зміни паролів / зміни ролей / виходів / тощо, щоб запобігти зловживанням (принаймні, поки вони не закінчуються).
java-addict301

38

Тут GETможна зловживати одним із способів - це те, що людина (можливо, конкурент) розмістив тег зображення з src="<your logout link>"будь-якою в Інтернеті, і якщо користувач вашого сайту натрапить на цю сторінку, він несвідомо вийде з системи.


4
Ні, це неправильно. Посилання для виходу буде працювати лише в тому випадку, якщо будуть надіслані правильні дані cookie, які не будуть з іншого домену. І навіть якщо ідентифікатор сеансу зберігається в URL-адресі, це не працюватиме, оскільки вони змінюються для кожного сеансу.
Річард Н

4
Нічого собі, я ніколи про це не думав! Отже, ще одна причина не використовувати GET, і ще одна причина, я не розумію, чому це роблять усі. Чорт, тепер я temped включити stackoverflow.com/users/logout «образ» теж мій пост і подивитися , що відбувається :-D
Daniel Ліуцці

24
src = простий запит браузера, він надходить не з сервера, а з клієнта. Він несе всі файли cookie та надходить з IP користувача. Ось чому пікселі відстеження реклами працюють. Єдиний спосіб визначити такий подвиг - перевірити реферала.
raveren

12
SuperLogout.com робить саме це (завантажує /logoutURL-адреси в приховані зображення), і це працює.
Дан Даскалеску

9
re: SuperLogout ... Я не знаю, чому я натиснув це.
М. І. Райт

21

Щоб бути правильним, GET / POST (або інші дієслова) - це дії на певному ресурсі (адресованому URL-адресою) - тож загалом про стан ресурсу, а не про стан програми як такого. Тож у справжніх духів у вас повинна бути така URL-адреса, як [host name]\[user name]\session, то "DELETE" - це правильне дієслово для виходу з системи.

Використання [host name]\bla bla\logoutв якості URL-адреси насправді не в повному обсязі REST (IMO), тож навіщо дискутувати про правильне використання GET / POST на ньому?

Звичайно, я також використовую GET для URL виходу у своїх програмах :-)


2
У такому випадку я б заперечував, що наявність частини [ім’я користувача] в URL-адресі видається непотрібною, оскільки користувачі завжди виходять із (тобто ВИДАЛИТИ) власного сеансу; ніколи інших користувачів ':-)
Daniel Liuzzi

1
Не дуже - ми говоримо, що сеанс - це ресурс, і ми хочемо його видалити. Тому для рівномірного звернення до будь-якого сеансу потрібно мати ім’я користувача як частину URL-адреси. Ваш аргумент настільки ж хороший, як сказати про те, що видавати дію PUT на [фотогалерея] \ малюнки означає, що ви додаєте до своїх фотографій (доступно на сторінці [фотогалерея] \ [ім'я користувача] \ фотографії). Різні ресурси повинні вирішуватись чітко, в них не може бути ніякої неявності. Цей сайт може дозволити іншим користувачам додавати фотографії у вашу галерею - це буде частиною контролю доступу так само, як у вас може бути супер користувач, який може вбивати будь-які сеанси.
VinayC

1
По-філософськи, ви можете назвати сеанси та фотографії "ресурсами", але реально я б не ставився до них однаково. Сеанс завжди суто обмежений для поточного користувача (звідси і назва Сесія), і, принаймні, в ASP.NET, немає ніякого способу доступу до сеансів іншого користувача. Навіть у розробника додатків немає прямого способу перерахувати всі активні сеанси, або означає знищити сеанси окремо. Ви можете перезапустити програму, щоб знищити всі сеанси (InProc), але я не закликав би цей контроль доступу. URL-адреси в стороні все ще залишається питання: GET або POST?
Даніель Люцці

Ресурс, отже, його адреса (URL) є важливою частиною REST. Отже, якщо ви вибрали URL, як я вже сказав, DELETE стає правильним словом - не GET або POST. Крім того, навіть якщо ви обмежуєте себе ASP.NET, ви завжди можете мати свого власного постачальника послуг, який може дати вам можливість перерахувати через сеанси та вбити інші сесії, якщо це потрібно. Для нестандартних сеансів, які не входять в комплект, деякі функції в global.asax повинні надавати вам функціональність. Це справді питання про те, потрібен би такий функціонал чи ні. Для рідкісних потреб люди прагнуть перезапустити веб-сайт, щоб виганяти людей із сайту.
VinayC

Це має для мене найбільше сенсу. Надайте веб-api маршруту сеансу та зателефонуйте на нього DELETE. Будь то ../session або ../session/current. Thanksx @VinayC
Саймон Хупер

16

Вихід із системи нічого не робить для самої програми. Це змінює стан користувача стосовно програми. У цьому випадку, здається, ваше питання більше базується на тому, як слід ініціювати команду від користувача, щоб розпочати цю дію. Оскільки це не "руйнівна дія", переконайтесь, що сеанс припинено або знищено, але ні ваша програма, ні ваші дані не змінюються, не можна дозволити обом методам ініціювати процедуру виходу з системи. Публікацію слід використовувати будь-які дії, ініційовані користувачем (наприклад, - користувач натискає "Вийти"), а get може бути зарезервовано для ініційованих заявок виходів (наприклад - виняток, який виявляє потенційне вторгнення користувача, насильно перенаправляє на сторінку входу за допомогою виходу GET ).


Цікаво; Я ніколи про це не думав. +1.
страгер

Це може залежати від програми (якась поведінка "каскадного видалення"), але ви праві.
Андрес Яан Так

@JoelEtherton Дякую, Джоел, я читав відповіді, цікавлячись, коли я дістанусь до потрібного. :)
Кирило Фукс

4
Це заплутано, оскільки вихід у систему змінює стан. POST - дієслово для зміни стану. GET призначений для отримання даних без громадянства. Це заплутано, оскільки ми очікуємо, що запити POST матимуть корисні навантаження. Як зазначалося нижче, DELETE буде найбільш правильним для об’єкта сеансу.
Майкл Коул

1
@MichaelCole: Я погодився б із таким уявленням про складність між POST та GET. Я б не погодився з використанням дієслова DELETE. DELETE призначений для обробки ресурсу, і сеанс не є ресурсом у цьому сенсі. Поміркуйте, якщо ви можете вилучити її, тоді ви також повинні мати можливість її встановити.
Джоель Етертон

16

Привіт, на мій погляд, коли ви входите, ви перевіряєте ім'я користувача / пароль, і якщо вони відповідають вам, ви створюєте маркер входу.

CREAT token => метод POST

Коли ви виходите з системи, ви відволікаєте маркер, тому для мене самим логічним методом має бути ВИКОРИСТАННЯ

DELETE token => метод DELETE


4
Цікавий кут.
Драмбег

1
Я використовую цей метод у своїх програмах Spring Boot REST.
Please_Dont_Bully_Me_SO_Lords

1
семантично правильні. Я згоден ...
DAG

1

Сценарій попереднього кешування є цікавим. Але я здогадуюсь, що якщо багато сайтів, включаючи ТАК, не переживайте з цього приводу, то, можливо, ви й не повинні.

Чи, можливо, посилання може бути реалізовано в JavaScript?

Редагувати: Як я розумію, технічно GET повинен бути для запитів лише для читання, які не змінюють стан програми. POST повинен бути для запитів / редагування запитів, які змінюють стан. Однак інші проблеми з додатком можуть віддати перевагу GET over POST для деяких запитів, що змінюються державою, і я не думаю, що в цьому є проблеми.


Дякую. Стан БД не буде змінено, але стан сеансу буде. Єдина проблема, яку я бачу - це та, про яку я згадував у запитанні, про те, що користувачів виганяють. Неруйнівний, але досить дратівливий. Зазвичай я проходжу мантру "якщо великі хлопці це роблять, значить, це має бути гаразд". Мені просто хотілося знати, яку думку з цього приводу мають інші.
Даніель Люцці

0

Добре, якщо ви забороняєте веб-програмі відмовлятися від сеансу через сценарій виходу, зазвичай вам це також не потрібно. Зазвичай існує змінна сесія, яка є унікальною для сеансу, який ви бажаєте залишити.


Чи можете ви розробити "сценарій виходу з системи"? Я не впевнений, якщо ви маєте на увазі встановлення терміну дії файлу cookie (що не виключає необхідності способу відпускати користувачів вручну.)
Daniel Liuzzi

Сценарій виходу із системи завершив би сеанс користувача (власне: браузера), викликавши його. На ASP.net, сеанс є об'єктом на сервері, від якого можна відмовитися. PHP має подібну систему. Оскільки цей браузер викликає скрипт, який закінчує сеанс, він уже знає, який закінчити, усуваючи потребу в змінних POST або GET.
Роб

1
Так, я тебе зараз отримую. У мене вже є сценарій, зокрема FormsAuthentication.SignOut (), але у мене питання про те, як викликати сценарій, як у GET або POST.
Даніель Люцці

О, у вас є URL-адреса у формі? Не має значення, чи не передаєте ви йому ніякої інформації. Найгірше, що може статися, це хтось відкриває сценарій вручну, виходячи з системи. Я б навіть не робив це полем форми, якщо це не потрібно, посилання на сценарій також буде працювати. Якщо ви дійсно надсилаєте інформацію до сценарію, я, ймовірно, перейду на пошту, щоб не показувати користувачеві будь-яку інформацію (якщо вони не переглядають джерело сторінки), і якщо вони оновлять, вони отримають попередження від свого браузера. (сторінка минула), що може бути бажаним.
Роб

0

Нещодавно я працював над проектом, який використовую GET для виходу. Нижче є код у Nodejs Express, і він працює чудово

ваш router.js

const express = require("express");
router.get("/signout", signout);

ваш controller.js

exports.signout  = (req, res) => {
        res.clearCookie('t'); //clearing cookie, which is 
            //assign to the user during sign in.          
            res.json({message : 'Signout success'});   
        };

-2

Я не бачу, наскільки виїзд (зменшення дозволів користувача) є дескруктивною дією. Це тому, що дія "виходу" має бути доступною лише тим користувачам, які вже ввійшли в систему, інакше це буде застарілим.

Випадково створена рядок, що міститься у файлах cookie вашого браузера, - це все, що представляє вашу сесію користувача. Існує безліч способів знищити його, щоб настільки ефективно вийти з системи - це лише послуга для вашого відвідувача.


2
wgetу павуковому режимі з правильним файлом cookie сеансу на приватній вікі - це було те, що я насправді повинен був зробити один раз. Звичайно, одна з перших сканованих URL-адрес була /logout.
Гельгі

5
Спробуйте перейти на SuperLogout.com, щоб побачити, наскільки /logoutнасправді є руйнівні GET-запити на сторінки. Наприклад, вам доведеться знову входити в Gmail, знову входити в чат, знаходити своє місце в усіх розмовах у Hangouts, які ви прокручували тощо. Це стосується лише Google.com.
Дан Даскалеску
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.