In order to force https, your RewriteRule is required to force an external redirect. In the case of your rule, you're forcing a 301 redirect (R=301
). Most browsers and clients are designed to automatically follow redirects, but they (incorrectly) do so with a GET request.
So, when a client sends a POST request with data to http://example.com/route
, your server responds with a 301 redirect to https://example.com/route
, and then the client makes a GET request without the data to the new URL. As you can see, you can't just change your routes to accept GET requests as well, because the data sent in the original POST request will be dropped.
One option would be to add a rewrite condition to not redirect POST requests:
# Force SSL
RewriteCond %{HTTPS} !=on
RewriteCond %{REQUEST_METHOD} !=POST
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
However, this pretty much defeats the purpose of what you're attempting to accomplish. This whole concept is to force https everywhere. It would be silly to enforce it everywhere except when POSTing data to your application.
Another possible option would be to change your 301 redirect to a 307 redirect. Even though clients aren't supposed to change the request method for 301/302 redirects, most clients do due to ambiguity in the specs and existing functionality. Because of this, 307 was added with the specific idea that if this status code is used, the request method MUST NOT be changed. However, 307 is classified as a "temporary redirect", so it won't be cached and may affect your SEO. Additionally, this status was added in the HTTP/1.1 spec, so you may run into some clients that don't know how to process a 307.
Your best option is probably just to reject non-secure POST requests. Or, redirect them to an error page explaining you don't accept non-secure POST requests.
RewriteEngine On
# Forbid non-secure POSTs
RewriteCond %{HTTPS} !=on
RewriteCond %{REQUEST_METHOD} =POST
RewriteRule ^ / [F,L]
# Force SSL
RewriteCond %{HTTPS} !=on
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…