Forum: NGINX URI re-mapping using try_files

Posted by mrtn (Guest)
on 2012-10-11 15:19
(Received via mailing list)
Hello,

I am new to nginx, and am still learning my way.

I use nginx to serve static html pages to users, and in particular, I 
want
users who visit 'www.example.com/public/doc/abc123?para=data' to be 
served
with the file '/home/www/example/public/doc/abc123/abc123.html' on the
server, but 'www.example.com/public/doc/abc123?para=data' stays in the
user's browser address bar.

So there are two issues here: 1. map URI pattern '/public/doc/blah' to 
file
'/home/www/example/public/doc/blah/blah.html' on the server; 2. keep 
query
string '?parap=data' in the address bar.

I wonder if these can be solved by using `try_files` within a location
block. For example, substring the $uri to take out '/blah' part, and 
append
it to the $uri followed by '.html'. And possibly append $args after 
'.html'?
How exactly do we do this in nginx? Thanks!

Posted at Nginx Forum: 
http://forum.nginx.org/read.php?2,231672,231672#msg-231672
Posted by Francis Daly (Guest)
on 2012-10-11 18:58
(Received via mailing list)
On Thu, Oct 11, 2012 at 09:19:23AM -0400, mrtn wrote:

Hi there,

> I use nginx to serve static html pages to users, and in particular, I want
> users who visit 'www.example.com/public/doc/abc123?para=data' to be served
> with the file '/home/www/example/public/doc/abc123/abc123.html' on the
> server, but 'www.example.com/public/doc/abc123?para=data' stays in the
> user's browser address bar.

For this sort of thing, "rewrite" (http://nginx.org/r/rewrite) is 
probably
the directive you want.

        rewrite (.*)/(.*) $1/$2/$2.html break;

can do what you want in this case.

What do you want to happen if the user asks for any of:

http://www.example.com/public/doc/abc123
http://www.example.com/public/doc/abc123?para=nodata
http://www.example.com/public/doc/abc123/abc123.html
http://www.example.com/public/doc/one/two

The rewrite directive above may or may not do what you want for those.

> So there are two issues here: 1. map URI pattern '/public/doc/blah' to file
> '/home/www/example/public/doc/blah/blah.html' on the server; 2. keep query
> string '?parap=data' in the address bar.

1) is in the rewrite (or any similar configuration which maps url to 
file)

2) is by virtue of not doing an external rewrite, which is a 
redirection.

  f
--
Francis Daly        francis@daoine.org
Posted by mrtn (Guest)
on 2012-10-11 22:00
(Received via mailing list)
Hi Francis,

Thanks for introducing me to rewrite directive. Just to confirm, this is 
how
I should use your rewrite:

root     /home/www/example;

location /public/doc/ {
    rewrite           (.*)/(.*) $1/$2/$2.html break;
}

Ideally, for the other cases you raised, I want the following to happen:

>http://www.example.com/public/doc/abc123
>http://www.example.com/public/doc/abc123?para=nodata

when the query string (e.g. ?para=blah) part is missing or incomplete, I
want to serve a generic error page (e.g. /error.html)

>http://www.example.com/public/doc/abc123/abc123.html

when the user tries to access the actual html page directly, I want to 
block
it by either returning a 404 or serving a generic error page as above

>http://www.example.com/public/doc/one/two

when the user queries an URI that has no corresponding .html file on the
server, I want to simply return a 404.

Can all these be implemented using rewrite only? Thanks.

Posted at Nginx Forum: 
http://forum.nginx.org/read.php?2,231672,231682#msg-231682
Posted by Francis Daly (Guest)
on 2012-10-11 22:32
(Received via mailing list)
On Thu, Oct 11, 2012 at 03:59:24PM -0400, mrtn wrote:

Hi there,

> Thanks for introducing me to rewrite directive. Just to confirm, this is how
> I should use your rewrite:
>
> root     /home/www/example;
>
> location /public/doc/ {
>     rewrite           (.*)/(.*) $1/$2/$2.html break;
> }

It can work outside of all locations, or else in the one location that
handles this request.

So this config can work.

> Ideally, for the other cases you raised, I want the following to happen:
>
> >http://www.example.com/public/doc/abc123
> >http://www.example.com/public/doc/abc123?para=nodata
>
> when the query string (e.g. ?para=blah) part is missing or incomplete, I
> want to serve a generic error page (e.g. /error.html)

The above rewrite pays no attention to query strings.

So you'll want to do something based on $arg_para -- maybe an "if"
or something involving "map".

I guess (without testing):

    if ($arg_para != data) { return 404; }

inside that location{} would probably work.

> >http://www.example.com/public/doc/abc123/abc123.html
>
> when the user tries to access the actual html page directly, I want to block
> it by either returning a 404 or serving a generic error page as above

The above rewrite does that (assuming that the "rewritten" file is 
absent).

> >http://www.example.com/public/doc/one/two
>
> when the user queries an URI that has no corresponding .html file on the
> server, I want to simply return a 404.

The above rewrite does that; but which html file should it look for 
here?

/home/www/example/public/doc/one/two/two.html, or
/home/www/example/public/doc/one/two/one/two.html?

(As in: do you repeat everything after /public/doc, or do you repeat
just the final after-slash part?)

> Can all these be implemented using rewrite only? Thanks.

With the extra "if" above, I think so.

Your testing should be able to show any problems, or unexpected 
behaviour.

  f
--
Francis Daly        francis@daoine.org
Posted by mrtn (Guest)
on 2012-10-11 23:23
(Received via mailing list)
Hi Francis,

>I guess (without testing):
>
>if ($arg_para != data) { return 404; }
>
>inside that location{} would probably work

Hmm, I read on nginx website and elsewhere that if statement may not 
work
consistently within a location directive, and is generally discouraged.
Should I worry in this case?

>The above rewrite does that; but which html file should it look for here?
>
>/home/www/example/public/doc/one/two/two.html, or
>/home/www/example/public/doc/one/two/one/two.html?
>
>(As in: do you repeat everything after /public/doc, or do you repeat
>just the final after-slash part?)

I only want to repeat the final after-slash part, so any
'/public/doc/blahA/blahB' should only look for
'/public/doc/blahA/blahB/blahB.html'. Would that change anything in the
config proposed here?

Thanks again!


Mrtn

Posted at Nginx Forum: 
http://forum.nginx.org/read.php?2,231672,231685#msg-231685
Posted by Francis Daly (Guest)
on 2012-10-12 00:13
(Received via mailing list)
On Thu, Oct 11, 2012 at 05:22:54PM -0400, mrtn wrote:

Hi there,

> >I guess (without testing):
> >
> >if ($arg_para != data) { return 404; }
> >
> >inside that location{} would probably work
>
> Hmm, I read on nginx website and elsewhere that if statement may not work
> consistently within a location directive, and is generally discouraged.
> Should I worry in this case?

What precisely did you read? And does it apply here?

(I think I know the answers to those; but there's no reason for you to
believe my words instead of words written elsewhere. If the words are
all consistent, then you can choose to believe them all. If the words 
are
contradictory, then you must choose which source to consider incorrect.)

> >(As in: do you repeat everything after /public/doc, or do you repeat
> >just the final after-slash part?)
>
> I only want to repeat the final after-slash part, so any
> '/public/doc/blahA/blahB' should only look for
> '/public/doc/blahA/blahB/blahB.html'. Would that change anything in the
> config proposed here?

What happened when you tried it?

mkdir -p /home/www/example/public/doc/blahA/blahB/blahA
echo This is in blahB > 
/home/www/example/public/doc/blahA/blahB/blahB.html
echo This is in blahA > 
/home/www/example/public/doc/blahA/blahB/blahA/blahB.html
curl -i http://www.example.com/public/doc/blahA/blahB

As it happens, the rewrite suggested should end up fetching the "in 
blahB"
file, because it only repeats the part after the last slash.

When you understand *why* it does that, you'll have a better chance of
writing your own regex-based rewrites.

Good luck with it!

  f
--
Francis Daly        francis@daoine.org
Please log in before posting. Registration is free and takes only a minute.
Existing account (Switch to SSL-encrypted connection)
NEW: Do you have a Google/GoogleMail or Yahoo account? No registration required!
Log in with Google account | Log in with Yahoo account
No account? Register here.