When working with legacy URLs, we often need to convert query string parameters into clean, SEO-friendly path segments. The specific case we're examining involves transforming:
/somefolder/mypage.aspx?myid=4343&tab=overview
into the more readable format:
/folder/4343/overview/
The common mistake in Nginx rewrite rules for query strings is that the ?
and following parameters aren't actually part of the URI that the rewrite directive matches against. Nginx processes the path portion before the ?
separately from the query string.
We need to use Nginx's $args
or $query_string
variables to access the query parameters:
location /somefolder/mypage.aspx {
if ($args ~* "myid=([^&]+)&tab=overview") {
rewrite ^ /folder/%1/overview/? permanent;
}
}
For better maintainability, consider using a map directive:
map $args $new_uri {
default "";
"~*^myid=(?[^&]+)&tab=overview" /folder/$id/overview/;
}
server {
...
location /somefolder/mypage.aspx {
if ($new_uri) {
rewrite ^ $new_uri? permanent;
}
}
}
After implementing the rule, test with:
curl -I "http://yourserver/somefolder/mypage.aspx?myid=4343&tab=overview"
You should receive a 301 redirect to the new clean URL format.
Many developers struggle when trying to convert query string parameters to clean URL paths in Nginx. The main issue is that Nginx's rewrite
directive doesn't process query strings by default - they need to be handled separately through the $args
or $query_string
variables.
The attempts shown in the question fail because:
- Nginx's rewrite regex doesn't match against query strings
- The question mark needs special escaping in regex patterns
- Ampersands in URLs can cause parsing issues
Here's the correct way to implement this rewrite:
location /somefolder/mypage.aspx {
if ($args ~* "myid=([^&]+)&tab=overview") {
set $myid $1;
rewrite ^ /folder/$myid/overview/ permanent;
}
}
For more complex scenarios, consider using Nginx's map directive:
map $args $new_path {
default "";
"~*myid=(?[^&]+)&tab=overview" /folder/$id/overview/;
}
server {
...
location /somefolder/mypage.aspx {
if ($new_path) {
return 301 $new_path;
}
}
}
When implementing query string rewrites:
- Always test with both trailing slashes and without
- Consider using 301 (permanent) vs 302 (temporary) redirects
- Remember that query string order might vary ($arg_ variables can help)
- URL-encode special characters when necessary
Here's a full server block implementation:
server {
listen 80;
server_name example.com;
location /somefolder/mypage.aspx {
if ($args ~* "myid=(?[^&]+)&tab=overview") {
return 301 /folder/$id/overview/;
}
# Handle other cases or pass to backend
proxy_pass http://backend;
}
location /folder {
# Your actual content handler for the new URLs
try_files $uri $uri/ =404;
}
}