Проблемы с маршрутизацией в Cake PHP 4.0.3 «Не найден маршрут, соответствующий X» - PullRequest
0 голосов
/ 14 февраля 2020

Я создаю веб-приложение, которое имеет внутренний REST API, написанный на Cake PHP 4.0.3, и пользовательский интерфейс, написанный на Vue. js 2.6.11, с использованием ax ios 0.19.2 для делать запросы.

Проблема в том, что я не могу вызвать метод DELETE ни на одной из моих конечных точек, и я не могу сказать, есть ли проблема в коде внешнего или внутреннего кода.

В в журнале сервера написано:

2020-02-14 10:55:54 Error: [Cake\Routing\Exception\MissingRouteException] A route matching "/meal-plans/14042e24-fa12-49d3-9bbe-91e57847a1c7" could not be found. in /var/www/html/vendor/cakephp/cakephp/src/Routing/RouteCollection.php on line 211
Exception Attributes: array (
  'url' => '/meal-plans/14042e24-fa12-49d3-9bbe-91e57847a1c7',
)
Stack Trace:
- /var/www/html/vendor/cakephp/cakephp/src/Routing/Router.php:227
- /var/www/html/vendor/cakephp/cakephp/src/Routing/Middleware/RoutingMiddleware.php:140
- /var/www/html/vendor/cakephp/cakephp/src/Http/Runner.php:73
- /var/www/html/vendor/cakephp/cakephp/src/Http/Runner.php:58
- /var/www/html/vendor/cakephp/cakephp/src/Http/Server.php:90
- /var/www/html/webroot/index.php:40

Request URL: /meal-plans/14042e24-fa12-49d3-9bbe-91e57847a1c7
Referer URL: http://localhost:8080/
Client IP: 172.19.0.1

Понимая, что это просто проблема маршрутизации, я набираю bin/cake routes в терминале:

+------------------+-----------------+------------------------------------------------------------------------------------+
| Route name       | URI template    | Defaults                                                                           |
+------------------+-----------------+------------------------------------------------------------------------------------+
| mealplans:index  | /meal-plans     | {"_method":"GET","action":"index","controller":"MealPlans","plugin":null}          |
| mealplans:add    | /meal-plans     | {"_method":"POST","action":"add","controller":"MealPlans","plugin":null}           |
| mealplans:view   | /meal-plans/:id | {"_method":"GET","action":"view","controller":"MealPlans","plugin":null}           |
| mealplans:edit   | /meal-plans/:id | {"_method":["PUT","PATCH"],"action":"edit","controller":"MealPlans","plugin":null} |
| mealplans:delete | /meal-plans/:id | {"_method":"DELETE","action":"delete","controller":"MealPlans","plugin":null}      |
| meals:index      | /meals          | {"_method":"GET","action":"index","controller":"Meals","plugin":null}              |
| meals:add        | /meals          | {"_method":"POST","action":"add","controller":"Meals","plugin":null}               |
| meals:view       | /meals/:id      | {"_method":"GET","action":"view","controller":"Meals","plugin":null}               |
| meals:edit       | /meals/:id      | {"_method":["PUT","PATCH"],"action":"edit","controller":"Meals","plugin":null}     |
| meals:delete     | /meals/:id      | {"_method":"DELETE","action":"delete","controller":"Meals","plugin":null}          |
+------------------+-----------------+------------------------------------------------------------------------------------+

Но, как вы можете видеть, он говорит о маршрутах загружены.

Я написал тест, чтобы увидеть, может ли он дать мне какие-либо подсказки. Тест должен был провалиться

class MealPlansControllerTest extends TestCase
{
    use IntegrationTestTrait;

    public $fixtures = [
        'app.MealPlans',
        'app.Meals'
    ];

    public function testDelete()
    {
        $this->assertCountRecords(1);

        $this->delete('/meal-plans/14042e24-fa12-49d3-9bbe-91e57847a1c7');
        $this->assertResponseCode(204);

        $this->assertCountRecords(0);
    }

    public function testDeleteInvalid()
    {
        $this->assertCountRecords(1);

        $this->delete('/meal-plans/14042f24-fa12-49d3-9bbe-91e57847a1c7');
        $this->assertResponseCode(404);

        $this->assertCountRecords(1);
    }

    private function assertCountRecords($expected)
    {
        $this->get('/meal-plans');
        $this->assertResponseCode(200);

        $body = json_decode((string) $this->_response->getBody(), true);
        $this->assertArrayHasKey('mealPlans', $body);
        $this->assertEquals($expected, count($body['mealPlans']));
    }

}

Но оба теста пройдены, так что он совсем не помог.

Итак, я застрял. Я понятия не имею, что происходит. Возможно, это что-то простое, но я не вижу этого.

Это неправильные маршруты:

/** @var RouteBuilder $routes */
$routes->setRouteClass(DashedRoute::class);
$routes->scope('/', function (RouteBuilder &$builder) {
    $builder->setExtensions(['json']);
    $builder->resources('MealPlans');
    $builder->resources('Meals');
});

Это контроллер, который я пытаюсь использовать:

/**
 * Class MealPlansController
 * @package App\Controller
 *
 * @property MealPlansTable $MealPlans
 */
class MealPlansController extends AppController
{
    public $modelClass = 'MealPlans';

    public function delete($id)
    {
        try {
            $mealPlan = $this->MealPlans->get($id);
        } catch (RecordNotFoundException $e) {
            $this->response = $this->response->withStatus(404, __d('meal_plans', 'delete_404'));
            return $this->render();
        }
        if ($this->MealPlans->delete($mealPlan)) {
            $this->response = $this->response->withStatus(204, __d('meal_plans', 'delete_200'));
        } else {
            $this->response = $this->response->withStatus(500, __d('meal_plans', 'delete_500'));
        }
        return $this->render();
    }
}

Внешний вызов выглядит следующим образом:

deleteMealPlan (mealPlan) {
    axios.delete('http://localhost:11000/meal-plans/' + mealPlan.id)
        .then((response) => {
            console.log(response.statusText);
            this.$store.dispatch('planner/syncMealPlans').then(() => this.$forceUpdate());
        });
}

И вызываемая конечная точка выглядит как http://localhost:11000/meal-plans/14042e24-fa12-49d3-9bbe-91e57847a1c7

Я могу получить вышеуказанную конечную точку просто отлично, я не проверял PUT или PATCH пока нет.

Единственный другой релевантный фрагмент кода - это мое промежуточное ПО:

$middlewareQueue
    ->add(new ErrorHandlerMiddleware(Configure::read('Error')))
    ->add(new AssetMiddleware([
        'cacheTime' => Configure::read('Asset.cacheTime'),
    ]))
    ->add(new RoutingMiddleware($this))
    ->add(new BodyParserMiddleware(['json' => true]))
    ->add(function (ServerRequest $request, Response $response, $next) {
        // Allow CORS
        return $next($request, $response)
            ->withHeader('Access-Control-Allow-Origin', '*')
            ->withHeader('Access-Control-Allow-Headers', '*')
            ->withHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, PATCH, DELETE');
    });

1 Ответ

0 голосов
/ 14 февраля 2020

Это была проблема с моим промежуточным ПО.

Я знал, что веб-браузеры отправляют запрос перед полетом, и, включив заголовки CORS, я думал, что закрыл себя.

Однако

Я разрешал все запросы на go через независимо от метода запроса. Это позволит запросам OPTIONS go проходить к маршрутизатору.

Когда маршрутизатор попытается проанализировать запрос и получить правильный маршрут, он не сможет найти маршруты с OPTIONS, определенными в параметре _method и выдает ошибку.

И это объясняет, почему мои тесты проходили. Поскольку запрос OPTIONS никогда не выполнялся, ошибка никогда не возникала.

Таким образом, решение состоит в том, чтобы вернуться раньше, если запрос является запросом OPTIONS

function (ServerRequest $request, Response $response, $next) {
    if ($request->getMethod() === 'OPTIONS') {
        return $response
            ->withHeader('Access-Control-Allow-Origin', '*')
            ->withHeader('Access-Control-Allow-Headers', '*')
            ->withHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, PATCH, DELETE');
    } else {
        $response = $next($request, $response)
            ->withHeader('Access-Control-Allow-Origin', '*')
            ->withHeader('Access-Control-Allow-Headers', '*')
            ->withHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, PATCH, DELETE');

        return $response;
    }
}
...