如何請求接口服務
HTTP協議下的請求方式
對於PhalApi,默認是通過HTTP協議進行通信的。根據接口服務的具體實現,可以使用GET或POST方式請求。
訪問入口
如前面所言,PhalApi推薦將系統對外可訪問的根目錄設置爲/path/to/phalapi/public。PhalApi的統一訪問入口文件是/path/to/phalapi/public/index.php文件。
當配置的域名爲:dev.phalapi.net,並且已將根目錄設置到public,此時訪問的URL是:
http://dev.phalapi.net
當未配置域名,亦未配置根目錄時,此時訪問的URL是(顯然更長更不優雅):
http://localhost/phalapi/public/index.php
如果尚未安裝,請先閱讀下載與安裝。
如何指定待請求的接口服務?
默認情況下,可以通過s參數指定待請求的接口服務,當s未傳時,缺省使用默認接口服務,即:App.Site.Index。以下三種方式是等效的,都是請求默認接口服務。
未傳s參數
?s=Site.Index,省略命名空間,默認使用App
?s=App.Site.Index,帶有命名空間前綴
也就是說,當請求除默認接口服務以外的接口服務時,其格式可以二選一:
?s=Class.Action
或者:?s=Namespace.Class.Action
其中,Namespace表示命名空間前綴,Class爲接口服務類名,Action爲接口服務方法名,這三者通常首字母大寫,並使用英文點號分割。最終執行的類方法是:Namespace/Api/Class::Action()。需要注意的是:
溫馨提示:s參數爲service參數的縮寫,即使用?s=Class.Action等效於?service=Class.Action,兩者都存在時優先使用service參數。
關於Namespace命名空間
Namespace是指命名空間中/Api/的前半部分。並且需要在根目錄下的composer.json文件中進行autoload的註冊,以便能正常自動加載類文件。如默認已經註冊的App命名空間:
{
"autoload": {
"psr-4": {
"App\\": "src/app"
}
}
}
當命名空間存在子命名空間時,在請求時使用下劃線分割。反過來,當不存在多級命名空間時,命名空間不應該含有下劃線。
關於Class接口服務類名
Class接口服務類名是指命名空間中/Api/的後半部分,並且必須是PhalApi/Api的子類。當命名空間存在子命名空間時,在請求時同樣改用下劃線分割。類似的,當不存在多級命名空間時,命名空間不應該含有下劃線。
關於Action接口服務方法名
待請求的Action,應該是public訪問級別的類方法,並且不能是PhalApi/Api已經存在的方法。
一些示例
以下是一些綜合的示例。
PhalApi 2.x 請求的s參數 對應的文件 執行的類方法
無 ./src/app/Api/Site.php App\Api\Site::Index()
?s=Site.Index ./src/app/Api/Site.php App\Api\Site::index()
?s=Weibo.Login ./src/app/Api/Weibo.php App\Api\Weibo::login()
?s=User.Weibo.Login ./src/user/Api/Weibo.php User\Api\Weibo::login()
?s=Company_User.Third_Weibo.Login ./src/company_user/Api/Third/Weibo.php Company\User\Api\Third\Weibo::login()
上面示例中假設,已經在composer.json中配置有:
{
"autoload": {
"psr-4": {
"App\\": "src/app",
"User\\": "src/user",
"Company\\User\\": "src/company_user"
}
}
}
開啓URI路由匹配
注意!本功能需要PhalApi 2.7.0 及以上版本方可支持。
任何情況下,PhalApi都會優先通過service參數,其次是s參數(也就是service的短參數)來定位當前客戶端請求的是哪一個接口服務。
當客戶端未提供service參數,亦未提供s參數時,可以通過開啓sys.enable_uri_match嘗試進行URI路由匹配。
先通過幾個例子來了解開啓URI路由匹配後的訪問效果,以下效果是等效的。
# 通過service指定
http://dev.phalapi.net/?service=App.Usre.Login
# 開啓URI路由匹配後
http://dev.phalapi.net/App/User/Login
# 省略App默認命名空間
http://dev.phalapi.net?s=App.Usre.Login
# 開啓URI路由匹配後
http://dev.phalapi.net/User/Login
原理很簡單,當未提供service參數和s參數時,並且是開啓sys.enable_uri_match後,客戶端可以通過/Namespace/Class/Action這樣的URI訪問接口服務。
除了要在./config/sys.php修改enable_uri_match配置爲true外,還需要同步進行Rewrite規則配置,以便讓你的服務在未找到文件時把請求轉發給index.php處理。參考以下Nginx配置:
server {
listen 80;
server_name dev.phalapi.net;
root /path/to/phalapi/public;
charset utf-8;
# 開啓URI路由匹配
location / {
try_files $uri $uri/ $uri/index.php;
}
if (!-e $request_filename) {
rewrite ^/(.*)$ /index.php last;
}
location ~ \.php$ {
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
access_log logs/dev.phalapi.net.access.log;
error_log logs/dev.phalapi.net.error.log;
}
路由如何匹配?
開啓路由匹配,並且正確配置Nginx或Apache的Rewrite規則後,客戶端可以通過以下方式訪問接口服務:
常見的路徑:/Namespace/Class/Action
常見的路徑,且帶有GET參數:/Namespace/Class/Action?xx=123
常見的路徑,且前面包含index.php文件:/index.php/Namespace/Class/Action
常見的路徑,且同時包含index.php文件和GET參數:/public/index.php/Namespace/Class/Action?xx=123
類似地,如果Namespace是App,那麼可以忽略不寫,即有:
默認App,常見的路徑:/Class/Action
默認App,常見的路徑,且帶有GET參數:/Class/Action?xx=123
默認App,常見的路徑,且前面包含index.php文件:/index.php/Class/Action
默認App,常見的路徑,且同時包含index.php文件和GET參數:/public/index.php/Class/Action?xx=123
下面是針對登錄接口的例子:
// 常見的路徑
http://dev.phalapi.net/App/User/Login
// 常見的路徑,且帶有GET參數
http://dev.phalapi.net/App/User/Login?username=dogstar&password=123456
// 常見的路徑,且前面包含index.php文件
http://dev.phalapi.net/index.php/App/User/Login
// 常見的路徑,且同時包含index.php文件和GET參數(入口文件必須是index.php,前面目錄路徑可自定義)
http://dev.phalapi.net/public/index.php/App/User/Login?username=dogstar&password=123456
擴展:如何定製接口服務的傳遞方式?
雖然我們約定統一使用?s=Namespace.Class.Action的格式來傳遞接口服務名稱,但如果項目有需要,也可以採用其他方式來傳遞。例如類似於Yii框架的請求格式:?r=Namespace/Class/Action。
如果需要定製傳遞接口服務名稱的方式,可以重寫PhalApi\Request::getService()方法。以下是針對改用斜槓分割,並換用r參數名字的實現代碼片段。
// 文件 ./src/app/Common/Request.php
<?php
namespace App\Common;
class Request extends \PhalApi\Request {
public function getService() {
// 優先返回自定義格式的接口服務名稱
$service = $this->get('r');
if (!empty($service)) {
$namespace = count(explode('/', $service)) == 2 ? 'App.' : '';
return $namespace . str_replace('/', '.', $service);
}
return parent::getService();
}
}
實現好自定義的請求類後,需要在項目的DI配置文件./config/di.php進行註冊。在最後的加上一行:
$di->request = new App\Common\Request();
這時,便可以通過新的方式來進行接口服務的請求的了。即:
原來的方式 現在的方式
?s=Site.Index ?r=Site/Index
?s=App.Site.Index ?r=App/Site/Index
?s=Hello.World ?r=Hello/World
?s=App.Hello.World ?r=App/Hello/World
這裏有幾個注意事項:
1、重寫後的方法需要轉換爲原始的接口服務格式,即:Namespace.Class.Action,注意別遺漏命名空間。
2、爲保持兼容性,在取不到自定義的接口服務名稱參數時,應該返回parent::getService()。
如果想再進行URL路由的美化,可以結合重定向配置來使用。
例如Nginx參考配置:
if (!-e $request_filename) {
rewrite ^/(.*)$ /index.php?r=$1 last;
}
例如Apache參考配置:
<IfModule mod_rewrite.c>
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ index.php/?r=$1 [QSA,PT,L]
SetEnvIf Authorization "(.*)" HTTP_AUTHORIZATION=$1
</IfModule>
又如IIS參考配置:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.webServer>
<rewrite>
<rules>
<rule name="Imported Rule 1" stopProcessing="true">
<match url="^(.*)$" ignoreCase="false" />
<conditions>
<add input="{REQUEST_FILENAME}" matchType="IsDirectory" ignoreCase="false" negate="true" />
<add input="{REQUEST_FILENAME}" matchType="IsFile" ignoreCase="false" negate="true" />
</conditions>
<action type="Rewrite" url="index.php/?r={R:1}" appendQueryString="true" />
</rule>
</rules>
</rewrite>
</system.webServer>
</configuration>
最終效果會類似,當訪問:http://api.phalapi.net/user/login,就會變成:http://api.phalapi.net/?r=user/login,然後觸發上在的擴展規則,最終等效於:http://api.phalapi.net/?s=user.login