REST URI设计:版本号放在http header中,rewrite配置

REST API新版本上线后,旧版本要继续在线,所以要做多版本并行。

服务器代码目录

api.example.com/

                          0.1/

                               controller

                               model

                               htdocs/index.php

                          0.2/

                               controller

                               model

                               htdocs/index.php

之前做的URI是这样的:

curl http://api.example.com/0.2/users/1

web server需要做rewrite,把各个版本的请求路由到 {v}/www/index.php。

版本号的格式为:11.11.11,即([0-9]+\.)+[0-9]+

这时候apache这么配:

    DocumentRoot "/api.example.com/"
    ServerName api.example.com
    RewriteEngine On
    RewriteRule ^/(([0-9]+\.)+[0-9]+)/ /$1/www/index.php

更多的了解REST以后,觉得把版本号、access_token放在header中更符合资源的概念。

参考:http://www.ruanyifeng.com/blog/2011/09/restful.html

URI改成这样:

curl -H 'Accept:application/json; version=0.2' http://api.example.com/users/1

这个时候需要web server从header中解析到版本号,然后路由。

这个时候apache这么配:

    DocumentRoot "/api.example.com/"
    ServerName api.example.com
    RewriteEngine On
    RewriteCond  %{HTTP_ACCEPT}  version=(([0-9]+\.)+[0-9]+) 
    RewriteRule ^(.+)$ - [env=v:%1]
    RewriteCond  %{HTTP_ACCEPT}  version=(([0-9]+\.)+[0-9]+)
    RewriteRule  .*   /%{ENV:v}/htdocs/index.php
    #RewriteLogLevel 9
    #RewriteLog logs/api.example.com-rewrite_log

在网上查了半天,才试出来apache rewrite从header中取变量。

nginx 这么配:

server {
    listen       8080;
    server_name  api.example.com;
    root html/api;
    #access_log   logs/api.example.com/access.log combined buffer=32k;
    access_log   logs/api.example.com/trunk/access.log combined;
    error_log    logs/api.example.com/trunk/error.log;

    location = /robots.txt {
        expires 1d;
    }
    location = /favicon.ico {
        expires 1d;
    }

    location / {
        rewrite ^/$ /docs.php last;
        set $api_version "enabled";
        if ($uri ~ "((([0-9]+\.)+[0-9]+)|trunk)/docs/.*") {
            set $api_version $1;
            rewrite ^/((([0-9]+\.)+[0-9]+)|trunk)/docs/$ /$api_version/htdocs/docs/index.html break;
            rewrite ^/((([0-9]+\.)+[0-9]+)|trunk)/docs/(.*)$ /$api_version/htdocs/docs/$4 break;
        }
        if ($http_accept ~ "application/json; version=((([0-9]+\.)+[0-9]+)|trunk)") {
            set $api_version $1;
        }
        rewrite .* /$api_version/htdocs/index.php last;
    }

    location ~ \.php$ {
        fastcgi_pass   unix:/home/lnmp/php/var/run/php-fpm.sock;
        fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
        include        fastcgi_params;
    }

    error_page  404              /404.html;
    location = /404.html {
        root   html;
    }

    error_page  500 502 503 504  /50x.html;
    location = /50x.html {
        root   html;
    }
}

注意:nginx if中的rewrite不能直接使用$1,而要先set。

参考资料:

how to use a variable inside a nginx “if” regular expression

http://stackoverflow.com/questions/5859848/how-to-use-a-variable-inside-a-nginx-if-regular-expression

apache [env=ps:http] %{ENV:ps}

http://www.askapache.com/htaccess/http-https-rewriterule-redirect.html

apache rewrite 变量 %{}

http://httpd.apache.org/docs/current/mod/mod_rewrite.html#RewriteCond

apache rewrite %N $N

http://httpd.apache.org/docs/current/mod/mod_rewrite.html#RewriteRule

apache [E=VAR:VAL] [env

http://httpd.apache.org/docs/2.2/rewrite/flags.html#flag_e

截图:

原文地址:https://www.cnblogs.com/sink_cup/p/rest_uri_rewrite_header_version_number.html