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
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
截图: