Laravel - CNAME + Subdomain Routing

百般思念 提交于 2020-01-01 03:55:29

问题


I have my routes set up as follows:

<?php

Route::group([
    'domain' => '{username}.u.'.env('APP_DOMAIN'),
], function () {
    Route::get('/', 'FrontendController@site');
});

Route::group([
    'domain' => env('APP_DOMAIN'),
], function () {
    // Regular site routes
});

Route::group([
    'domain' => '{domain}',
], function () {
    Route::get('/', 'FrontendController@domain');
});

What I'm trying to achieve is allowing users to have their own sites, e.g. hello.u.domain.com, and for those sites to also be served through a custom domain that is CNAME'd to their subdomain. Using the routing above, the wildcard subdomain works perfectly fine. However the custom domain routing is never hit; whenever a custom domain that is CNAME'd to the subdomain is visited, the regular site routes are used.

APP_DOMAIN is not the same as the custom domain, and I have $router->pattern('domain', '[a-z0-9.]+'); in my RouteServiceProvider.php to allow {domain} as a full domain name.


回答1:


Unfortunately I did not get an answer to my comment. This answer assumes the problem is that normal default routes are used instead of routes with subdomain.

Example:

A user is visiting sub.website.com but route() returns website.com/blabla instead of sub.website.com/blabla

You can solve this by dynamically create the pattern for domain inside routes.php

// routes.php
$url_parameters = @explode(".", $_SERVER['HTTP_HOST']);

if (count($url_parameters) == 3)
{
    $pattern = '{subdomain}.{domain}.{tld}';
}
else
{
    $pattern = '{domain}.{tld}';
}

Route::group(['domain' => $pattern], function () {

    Route::get('/', [
        'as' => 'get_index',
        'uses' => 'HomeController@getIndex'
    ]);

}

By using this method you will create a problem with your route() and controller parameters.

route() problem

When calling the route() function while using this method you will get a missing argument error. The route() function expects you to give the {subdomain}.{domain}.{tld} parameters.

You can solve this by creating your own route function. I named it mdroute() (multi domain route).

function mdroute($route, $parameters = [])
{

    $data = [
        'domain' => \Request::route()->domain,
        'tld' => \Request::route()->tld
    ];


    $subdomain = \Request::route()->subdomain;

    if ($subdomain) $data['subdomain'] = $subdomain;

    // You can use mdroute('blabla', 'parameter')
    // or mdroute('blabla', ['par1' => 'parameter1', 'par2' => 'parameter2'])
    //
    if (is_array($parameters))
    {
        $data = array_merge($data, $parameters);
    }
    else
    {
        $data[] = $parameters;
    }


    return route($route, $data);

}

Controller problem

The parameters {sub}.{domain}.{tld} are always send to your controller. You can't access other parameters the way you are used to be.

Example:

// Domain = sub.webite.com


// Your route
//
Route::get('/post/{id}/{param2}', [
    'uses' => 'PostController@getIndex'
]);

// PostController
//
public function getIndex($id, $param2)
{

    // $id will be 'sub'
    // $param2 will be 'website'

}

You can solve this by accessing your parameter through the Request object.

public function getIndex(Request $request)
{

    $id = $request->id;

    $param2 = $reqeust->param2;

}



回答2:


You can't have a wildcard on the whole domain, at least not with one wildcard. What you can do is the following:

Route::group([
    'domain' => '{domain}.{suffix}',
], function () {
    Route::get('/', 'FrontendController@domain');
});

Just make sure that this group is the last one in your routes file, it will act as a fallback group on domains and will serve the requests that don't match any of the previous domains.

Also I'd recommend using this package, it might be helpful for what you are trying to do.




回答3:


This has been answered, at least partially, by myself here: Creating a route in Laravel using subdomain and domain wildcards

In short, you cannot make the whole domain a parameter in the routes file. Instead, you assign a middleware that will check the current domain, match it against your pre-defined list of allowed user domains and based on that - take some decision (eg. what method to hit in your controller).

Consider:

Route::group([
    'middleware' => 'domain-check',
], function () {
    Route::get('/', 'FrontendController@handle');
});

And then in your FrontendController:

public function handle(Request $request)
{
    // Information about the current user/domain is here
    $request->client;

    // An example - let's imagine that client object contains a view ID
    return response()->view($request->client->view);
}


来源:https://stackoverflow.com/questions/37360369/laravel-cname-subdomain-routing

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!