Статьи

Создание простого API-прокси-сервера с PHP


Сейчас я играю с Backbone и использую публичный API в качестве источника.
Веб-браузер имеет одну ужасную особенность: он не позволяет вам извлекать какие-либо внешние ресурсы на наш хост из-за ограничений на разные источники. Например, если у нас есть сервер на локальном хосте, мы не можем выполнить один AJAX-запрос к другому хосту, отличному от локального хоста. В настоящее время есть заголовок, позволяющий это сделать:
Access-Control-Allow-Origin, Проблема в том, что удаленный сервер должен настроить этот заголовок. Например, я играл с API GitHub, и у GitHub нет этого заголовка. Если сервер является моим сервером, довольно просто поместить этот заголовок, но, очевидно, я не являюсь системным администратором github, поэтому я не могу этого сделать. Какое решение? Одним из возможных решений является, например, создание прокси-сервера на локальном хосте с PHP. С PHP мы можем использовать любой удаленный API с curl (я писал об этом
здесь и
здесьнапример). Это не сложно, но я спросил себя: можем ли мы создать фиктивный прокси-сервер с PHP для обработки любого запроса на локальный хост и перенаправления на реальный сервер, вместо того, чтобы создавать один прокси для каждого запроса? Давайте начнем. Вероятно, есть одно решение с открытым исходным кодом (скажите, знаете ли вы его), но я нахожусь в отпуске, и я хочу немного кодировать (я сейчас, это выглядит безумно, но это я
:)).

Идея заключается в следующем:

...
$proxy->register('github', 'https://api.github.com');
...

И когда я печатаю:

HTTP: // локальный / GitHub / пользователей / gonzalo123

и создайте прокси для:

https://api.github.com/users/gonzalo123

Метод запроса также важен. Если мы создаем POST-запрос к localhost, мы хотим, чтобы POST-запрос также выполнялся на github.

На этот раз мы не собираемся изобретать велосипед, поэтому мы будем использовать symfony componets, поэтому мы будем использовать composer для запуска нашего проекта:

Мы создаем файл conposer.json с зависимостями:

{
    "require": {
        "symfony/class-loader":"dev-master",
        "symfony/http-foundation":"dev-master"
    }
}

Теперь

php composer.phar install

И мы можем начать кодирование. Сценарий будет выглядеть так:

register('github', 'https://api.github.com');
$proxy->run();

foreach($proxy->getHeaders() as $header) {
    header($header);
}
echo $proxy->getContent();

Как мы видим, мы можем зарегистрировать столько серверов, сколько захотим. В этом примере мы регистрируем только github. Приложение имеет только два класса:
RestProxy , который извлекает информацию из объекта запроса и обращается к реальному серверу через CurlWrapper .

<?php
namespace RestProxy;

class RestProxy
{
    private $request;
    private $curl;
    private $map;

    private $content;
    private $headers;

    public function __construct(\Symfony\Component\HttpFoundation\Request $request, CurlWrapper $curl)
    {
        $this->request  = $request;
        $this->curl = $curl;
    }

    public function register($name, $url)
    {
        $this->map[$name] = $url;
    }

    public function run()
    {
        foreach ($this->map as $name => $mapUrl) {
            return $this->dispatch($name, $mapUrl);
        }
    }

    private function dispatch($name, $mapUrl)
    {
        $url = $this->request->getPathInfo();
        if (strpos($url, $name) == 1) {
            $url         = $mapUrl . str_replace("/{$name}", NULL, $url);
            $queryString = $this->request->getQueryString();

            switch ($this->request->getMethod()) {
                case 'GET':
                    $this->content = $this->curl->doGet($url, $queryString);
                    break;
                case 'POST':
                    $this->content = $this->curl->doPost($url, $queryString);
                    break;
                case 'DELETE':
                    $this->content = $this->curl->doDelete($url, $queryString);
                    break;
                case 'PUT':
                    $this->content = $this->curl->doPut($url, $queryString);
                    break;
            }
            $this->headers = $this->curl->getHeaders();
        }
    }

    public function getHeaders()
    {
        return $this->headers;
    }

    public function getContent()
    {
        return $this->content;
    }
}

RestProxy получает два экземпляра в конструкторе через внедрение зависимостей (CurlWrapper и Request). Эта архитектура очень помогает в тестах , потому что мы можем высмеивать оба экземпляра. Очень полезно при сборке RestProxy.

RestProxy зарегистрирован в packaist, поэтому мы можем установить его с помощью установщика composer:

Сначала установите компонент

curl -s https://getcomposer.org/installer | PHP

и создайте новый проект:

php composer.phar create-project gonzalo123 / rest-proxy proxy

Если мы используем PHP5.4 (если нет, чего вы ждете?), Мы можем запустить встроенный сервер

cd proxy
php -S localhost:8888 -t www/

Теперь нам нужно только открыть веб-браузер и набрать:

    http://localhost:8888/github/users/gonzalo123

Библиотека очень минимальна (этого достаточно для моего эксперимента) и не допускает авторизацию.

Конечно, полный код доступен в github .