WAMP服务器上.htaccess的RewriteRule致登录表单提交异常
我在Windows电脑上安装了WAMP Server,系统采用PHP Slim框架。当前遇到的问题:登录表单部署在http://localhost/login地址,提交表单时本该把数据发送到http://localhost/login/do,但实际却被重定向回http://localhost/login。这套代码在Linux服务器上运行正常,推测是.htaccess里的重写规则没考虑URL的后续部分导致。把表单提交URL改成http://localhost/DoLogin能解决,但希望不改提交URL来修复。
相关配置代码如下:
.htaccess 重写规则
RewriteEngine On RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule ^(contact|login|unsubscribe|activation|activation-again|forgot-pass|banned|manage-profile|manage-acount|profile-settings|terms|privacy|faq|blog|clubs|browse|basic_search|online|timeline|permission-requests|my-validations|my-fans|my-gifts|my-invitations|gift_wheel|gift_select|my-visitors|my-reviews|my-blocklist|my_pictures|my_videos|my_xcoins|xcoin_acount|what_is_matcmeter|what_is_trust_score|medical_reports|picture|video|webcam_verification|quick_settings|my_messages|my_messagesV2|my_orders|site-maps|logout|welcome|signup|data/xcoin_islem_list)$ /$1.php?lang=en [L] RewriteRule /faq/detail/(.*?)/(.*?)/(.*?)/(.*?)?$ /faq_detail.php?t_tbl=faq_contents&t_cat_id=$1&t_cat_name=$2&t_id=$3&t_title=$3 [QSA,NC,L] RewriteRule /faq/categories/(.*?)/(.*?)?$ /faq_categories.php?t_tbl=faq_categories&t_cat_id=$1&t_cat_name=$2 [QSA,NC,L] RewriteRule /blog/detail/(.*?)/(.*?)/(.*?)/(.*?)?$ /blog_detail.php?t_tbl=blog_contents&t_cat_id=$1&t_cat_name=$2&t_id=$3&t_title=$3 [QSA,NC,L] RewriteRule /blog/categories/(.*?)/(.*?)?$ /blog_categories.php?t_tbl=blog_categories&t_cat_id=$1&t_cat_name=$2 [QSA,NC,L] RewriteRule /profile/(.*?)?$ /member_profile.php?t_tbl=members&name=$1 [QSA,NC,L] RewriteRule /create-events/(.*?)?$ /create-events.php?id=$1 [QSA,NC,L] RewriteRule /show-feedback/(.*?)/(.*?)?$ /show-feedback.php?id=$1&name=$2 [QSA,NC,L] RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule ^ /api/index.php [QSA,NC,L]
登录表单代码
<div class="sign-user_card rounded pl-2 pr-2 pt-3 pb-3 shadow"> <div class="sign-in-page-data"> <div class="sign-in-from w-100 m-auto"> <form class="mt-4" method="post" action="/login/do"> <div class="form-group"> <label>E-mail address</label> <input type="text" value="" class="form-control kar_tem_func" name="f_user" id="f_user"> </div> <div class="form-group"> <label>Password</label> <input type="password" value="" class="form-control kar_tem_func" name="f_pass" id="f_pass"> </div> </form> </div> </div> <div class="d-flex justify-content-center links"> <input type="submit" class="btn btn-primary btn-block">Log in</input> </div> </div>
Slim 路由配置
$app->post('/login/do', function (Request $request, Response $response) { /* The login operations take place here. */ $alert_text= 'OK!'; return $response ->withStatus(200) ->withHeader("Content-Type", 'application/json') ->withJson(array([ "id" => 1, "alert_text" => $alert_text ])); exit(); });
问题出在.htaccess的第一条重写规则上:这条规则用^(xxx)$匹配URL,但Windows环境下的Apache会把^login$误匹配到/login/do的前缀部分,导致/login/do被直接重写为/login.php?lang=en,根本到不了Slim的路由处理逻辑。
不用改表单提交URL,只要调整这条重写规则,确保它只匹配精确的一级路径,不会拦截带后续子路径的请求就行,有两种可行的改法:
改法一:精确匹配路径
把第一条规则的正则表达式改成^/(xxx)/?$,明确只匹配以/xxx开头且没有后续子路径的请求(允许末尾带斜杠):
RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule ^/(contact|login|unsubscribe|activation|activation-again|forgot-pass|banned|manage-profile|manage-acount|profile-settings|terms|privacy|faq|blog|clubs|browse|basic_search|online|timeline|permission-requests|my-validations|my-fans|my-gifts|my-invitations|gift_wheel|gift_select|my-visitors|my-reviews|my-blocklist|my_pictures|my_videos|my_xcoins|xcoin_acount|what_is_matcmeter|what_is_trust_score|medical_reports|picture|video|webcam_verification|quick_settings|my_messages|my_messagesV2|my_orders|site-maps|logout|welcome|signup|data/xcoin_islem_list)/?$ /$1.php?lang=en [L]
改法二:添加排除条件
给第一条规则加个额外的条件,直接排除所有包含第二个斜杠的请求,确保只有一级路径会被重写:
RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d # 排除带子路径的请求(比如/login/do这种有两个斜杠的) RewriteCond %{REQUEST_URI} !^/[^/]+/ RewriteRule ^(contact|login|unsubscribe|activation|activation-again|forgot-pass|banned|manage-profile|manage-acount|profile-settings|terms|privacy|faq|blog|clubs|browse|basic_search|online|timeline|permission-requests|my-validations|my-fans|my-gifts|my-invitations|gift_wheel|gift_select|my-visitors|my-reviews|my-blocklist|my_pictures|my_videos|my_xcoins|xcoin_acount|what_is_matcmeter|what_is_trust_score|medical_reports|picture|video|webcam_verification|quick_settings|my_messages|my_messagesV2|my_orders|site-maps|logout|welcome|signup|data/xcoin_islem_list)$ /$1.php?lang=en [L]
原理说明
两种改法都是为了让/login/do这种带子路径的请求跳过第一条重写规则,继续往下执行,最终被最后一条规则转到Slim的api/index.php,从而触发对应的/login/do路由处理表单提交。这样就不用修改表单的提交URL,直接在.htaccess里调整规则就能解决问题。
内容的提问来源于stack exchange,提问作者EBoz

