我正在将一个电子商务网站转移到一个新的购物篮。出于某种原因,旧网站使用破折号表示类别,但使用下划线表示产品。
因此,产品的完整 URL 如下所示:
http://www.example.com/Engineering-Common-Bricks/65mm_Class_B__Solid_Engineering_Brick__Price_Each
新的购物篮对所有内容都使用了破折号,因此我需要将上述传入 URL 重写为以下内容:
http://www.example.com/Engineering-Common-Bricks/65mm-Class-B--Solid-Engineering-Brick--Price-Each
我知道有很多关于将下划线重写为破折号的资料,但它们似乎都不适合我。
我正在使用 Opencart,它带有一组现有的重写规则,因此这些规则可能会干扰我尝试添加的新规则。
现有的.htaccess
如下:
Options +FollowSymlinks
# Prevent Directoy listing
Options -Indexes
# Prevent Direct Access to files
<FilesMatch "\.(tpl|ini|log)">
Order deny,allow
Deny from all
</FilesMatch>
# SEO URL Settings
RewriteEngine On
# If your opencart installation does not run on the main web folder make sure you folder it does run in ie. / becomes /shop/
RewriteBase /
RewriteRule ^sitemap.xml$ index.php?route=feed/google_sitemap [L]
RewriteRule ^googlebase.xml$ index.php?route=feed/google_base [L]
RewriteRule ^download/(.*) /index.php?route=error/not_found [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} !.*\.(ico|gif|jpg|jpeg|png|js|css)
RewriteRule ^([^?]*) index.php?_route_=$1 [L,QSA]
任何帮助或指导都将不胜感激。
按照 Esa 的回答更新.htaccess
如下:
Options +FollowSymlinks
Options -Indexes
<FilesMatch "\.(tpl|ini|log)">
Order deny,allow
Deny from all
</FilesMatch>
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^([^_]*)_([^_]*_.*) $1-$2 [N]
RewriteRule ^([^_]*)_([^_]*)$ /$1-$2 [L,R=301]
RewriteBase /
RewriteRule ^sitemap.xml$ index.php?route=feed/google_sitemap [L]
RewriteRule ^googlebase.xml$ index.php?route=feed/google_base [L]
RewriteRule ^download/(.*) /index.php?route=error/not_found [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} !.*\.(ico|gif|jpg|jpeg|png|js|css)
RewriteRule ^([^?]*) index.php?_route_=$1 [L,QSA]
适用于:
http://example.com/this_is_a_category
但会导致 Apache 崩溃:
http://example.com/this_is_a_category/this_is_a_product
答案1
由于 RewriteRules 用于正则表达式匹配而不是替换,因此
RewriteRule ^([^_]*)_([^_]*_.*) $1-$2 [N]
RewriteRule ^([^_]*)_([^_]*)$ /$1-$2 [L,R=301]
不重复。因此,你需要为每一行添加下划线,例如
RewriteRule ^(.*)_(.*)_(.*)_(.*)_(.*)_(.*)_(.*)$ /$1-$2-$3-$4-$5-$6-$7 [R=301,L]
RewriteRule ^(.*)_(.*)_(.*)_(.*)_(.*)_(.*)$ /$1-$2-$3-$4-$5-$6 [R=301,L]
RewriteRule ^(.*)_(.*)_(.*)_(.*)_(.*)$ /$1-$2-$3-$4-$5 [R=301,L]
RewriteRule ^(.*)_(.*)_(.*)_(.*)$ /$1-$2-$3-$4 [R=301,L]
RewriteRule ^(.*)_(.*)_(.*)$ /$1-$2-$3 [R=301,L]
RewriteRule ^(.*)_(.*)$ /$1-$2 [R=301,L]
替换 1-5 个下划线,结果为
/Engineering_Common_Bricks/65mm_Class_B-Solid-Engineering-Brick-Price-Each
因此,对于 9 个替换,您需要在顶部添加几行。模式将相同,但较长的表达式需要放在最前面。
但是,这会将所有下划线替换为破折号(并在最后一个下划线后重定向),因此您不能使用任何包含下划线的文件名。您也可以通过在这些规则之前添加 RewriteCond 指令来防止这种情况发生:
RewriteCond %{REQUEST_FILENAME} !-f
答案2
RewriteRule ^([^_]*)_([^_]*_.*) $1-$2 [N] RewriteRule ^([^_]*)_([^_]*)$ /$1-$2 [L,R=301]
适用于:
http://example.com/this_is_a_category
但会导致 Apache 崩溃:
http://example.com/this_is_a_category/this_is_a_product
要解决这个问题,您只需DPI
在第一个RewriteRule
指令中添加(丢弃路径信息)标志:
RewriteRule ^([^_]*)_([^_]*_.*) $1-$2 [N,DPI]
RewriteRule ^([^_]*)_([^_]*)$ /$1-$2 [L,R=301]
“Apache 崩溃”是由于无尽的重写循环。该N
标志导致规则集循环(在这种情况下,这是必需的,以便替换除一个下划线之外的所有内容),但是,原始请求的路径信息会在每次迭代时附加到重写的 URL 中(根据设计)。
在第一个示例中,只有一个路径段,没有额外的路径信息,因此没有附加任何内容。但是,第二个示例包含额外的路径信息,即/this_is_a_product
(第一个路径段之后未映射到物理文件系统路径的所有内容) - 它本身包含下划线。这就是问题所在。循环的每次迭代只替换一个下划线,但循环的每次迭代还会附加 3 个下划线(在此示例中)!因此,它永远无法完成替换所有(除一个外)下划线的任务!
如果启用重写日志记录,错误日志将报告类似以下内容:
/this_is_a_category/this_is_a_product
/this-is_a_category/this_is_a_product/this_is_a_product
/this-is-a_category/this_is_a_product/this_is_a_product/this_is_a_product
/this-is-a-category/this_is_a_product/this_is_a_product/this_is_a_product/this_is_a_product
/this-is-a-category/this-is_a_product/this_is_a_product/this_is_a_product/this_is_a_product/this_is_a_product
:
如您所见,这很快就会失控。默认情况下,它会在 32,000 次迭代后停止(!),但您的服务器可能在此之前就耗尽了资源;因此崩溃。在 Apache 2.4.8+ 上,您可以限制迭代次数,例如N=10
- 虽然这不能解决您的问题,但它会阻止您的服务器崩溃!
据我所知,该DPI
标志(Apache 2.2.12+)是专门为解决此问题而创建的。它会丢弃重写 URL 中的原始路径信息,因此不会每次都重新附加,从而防止无限重写循环。