Prefix Rewrite
PrefixRewrite is a route feature that allows you to replace (rewrite) the matched request path with a specified value before sending it upstream.
Routes are processed in order, so the first matching request path is the only one that will be processed.
Setting prefixRewrite to "" is ignored. It’s interpreted the same as if you did not provide any value at all, i.e., do NOT rewrite the path.
Example
Install gloo gateway
glooctl install gateway
Install the petstore demo
kubectl apply -f https://raw.githubusercontent.com/solo-io/gloo/v1.14.x/example/petstore/petstore.yaml
Create a virtual service with routes for /foo
and /bar
kubectl apply -f - << EOF
apiVersion: gateway.solo.io/v1
kind: VirtualService
metadata:
name: 'default'
namespace: 'gloo-system'
spec:
virtualHost:
domains:
- '*'
routes:
- matchers:
- prefix: '/foo'
routeAction:
single:
upstream:
name: 'default-petstore-8080'
namespace: 'gloo-system'
options:
prefixRewrite: '/api/invalid'
- matchers:
- prefix: '/bar'
routeAction:
single:
upstream:
name: 'default-petstore-8080'
namespace: 'gloo-system'
options:
prefixRewrite: '/api/pets'
status: {}
EOF
These routes use prefix rewrite to change the request path before sending it upstream to the petstore microservice.
The petstore microservice lacks the /api/invalid
endpoint, so the following command fails when handled upstream.
curl "$(glooctl proxy url)/foo"
returns
{"code":404,"message":"path /api/invalid was not found"}
Meanwhile the following command rewrites the /bar
to the /api/pets
endpoint, which the petstore microservice supports.
curl "$(glooctl proxy url)/bar"
returns
[{"id":1,"name":"Dog","status":"available"},{"id":2,"name":"Cat","status":"pending"}]
We have successfully shown how you can change the external API of your services without changing the services themselves.
Avoiding the //
rewrite problem
When rewriting routes you must be careful with trailing backslashes. For example, the following naïve virtual service looks fine
kubectl apply -f - << EOF
apiVersion: gateway.solo.io/v1
kind: VirtualService
metadata:
name: 'default'
namespace: 'gloo-system'
spec:
virtualHost:
domains:
- '*'
routes:
- matchers:
- prefix: '/foo'
routeAction:
single:
upstream:
name: 'default-petstore-8080'
namespace: 'gloo-system'
options:
prefixRewrite: '/'
status: {}
EOF
When you curl /foo
the request path is rewritten to /
as you would expect
curl "$(glooctl proxy url)/foo"
returns
{"code":404,"message":"path / was not found"}
But requests to /foo/
(often a valid request) may surprise you
curl "$(glooctl proxy url)/foo/"
returns
{"code":404,"message":"path // was not found"}
To avoid this problem, we (and Envoy) recommend two matchers, one for each case (order matters)
kubectl apply -f - << EOF
apiVersion: gateway.solo.io/v1
kind: VirtualService
metadata:
name: 'default'
namespace: 'gloo-system'
spec:
virtualHost:
domains:
- '*'
routes:
- matchers:
- prefix: '/foo/'
routeAction:
single:
upstream:
name: 'default-petstore-8080'
namespace: 'gloo-system'
options:
prefixRewrite: '/'
- matchers:
- prefix: '/foo'
routeAction:
single:
upstream:
name: 'default-petstore-8080'
namespace: 'gloo-system'
options:
prefixRewrite: '/'
status: {}
EOF
Now /foo/
rewrites to /
, as desired
curl "$(glooctl proxy url)/foo/"
returns
{"code":404,"message":"path / was not found"}
Cleanup
glooctl uninstall
kubectl delete -f https://raw.githubusercontent.com/solo-io/gloo/v1.14.x/example/petstore/petstore.yaml