Laravel - CNAME + 子域路由
Laravel - CNAME + Subdomain Routing
我的路线设置如下:
<?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');
});
我想要实现的是让用户拥有自己的网站,例如hello.u.domain.com,并且这些网站也可以通过 CNAME 到其子域的自定义域提供服务。使用上面的路由,通配符子域工作得很好。然而,自定义域路由永远不会被命中;每当访问子域的 CNAME 自定义域时,都会使用常规站点路由。
APP_DOMAIN
和自定义域名不一样,我的RouteServiceProvider.php
里面有$router->pattern('domain', '[a-z0-9.]+');
允许{domain}
作为完整域名。
您不能在整个域上使用通配符,至少不能使用一个通配符。您可以做的是:
Route::group([
'domain' => '{domain}.{suffix}',
], function () {
Route::get('/', 'FrontendController@domain');
});
只需确保该组是您的路由文件中的最后一个,它将充当域上的后备组,并将处理与之前任何域都不匹配的请求。
此外,我建议使用 this package,它可能对您尝试做的事情有所帮助。
我在这里至少部分地回答了这个问题:
简而言之,您不能将整个域作为路由文件中的参数。相反,您分配一个中间件来检查当前域,将其与您预定义的允许用户域列表进行匹配,并基于此做出一些决定(例如,在您的控制器中使用什么方法)。
考虑:
Route::group([
'middleware' => 'domain-check',
], function () {
Route::get('/', 'FrontendController@handle');
});
然后在您的 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);
}
很遗憾,我的评论没有得到答复。该答案假定问题是使用普通默认路由而不是具有子域的路由。
示例:
用户正在访问 sub.website.com 但 route() returns 网站。com/blabla 而不是 sub.website。com/blabla
您可以通过在 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'
]);
}
使用此方法会导致 route() 和控制器参数出现问题。
route()问题
在使用此方法的同时调用 route() 函数时,您将收到缺少参数的错误。 route() 函数需要您提供 {subdomain}.{domain}.{tld} 参数。
您可以通过创建自己的路由函数来解决这个问题。我将其命名为 mdroute()(多域路由)。
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);
}
控制器问题
参数 {sub}.{domain}.{tld} 总是发送到您的控制器。您不能像以前那样访问其他参数。
示例:
// 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'
}
您可以通过请求对象访问您的参数来解决这个问题。
public function getIndex(Request $request)
{
$id = $request->id;
$param2 = $reqeust->param2;
}
我的路线设置如下:
<?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');
});
我想要实现的是让用户拥有自己的网站,例如hello.u.domain.com,并且这些网站也可以通过 CNAME 到其子域的自定义域提供服务。使用上面的路由,通配符子域工作得很好。然而,自定义域路由永远不会被命中;每当访问子域的 CNAME 自定义域时,都会使用常规站点路由。
APP_DOMAIN
和自定义域名不一样,我的RouteServiceProvider.php
里面有$router->pattern('domain', '[a-z0-9.]+');
允许{domain}
作为完整域名。
您不能在整个域上使用通配符,至少不能使用一个通配符。您可以做的是:
Route::group([
'domain' => '{domain}.{suffix}',
], function () {
Route::get('/', 'FrontendController@domain');
});
只需确保该组是您的路由文件中的最后一个,它将充当域上的后备组,并将处理与之前任何域都不匹配的请求。
此外,我建议使用 this package,它可能对您尝试做的事情有所帮助。
我在这里至少部分地回答了这个问题:
简而言之,您不能将整个域作为路由文件中的参数。相反,您分配一个中间件来检查当前域,将其与您预定义的允许用户域列表进行匹配,并基于此做出一些决定(例如,在您的控制器中使用什么方法)。
考虑:
Route::group([
'middleware' => 'domain-check',
], function () {
Route::get('/', 'FrontendController@handle');
});
然后在您的 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);
}
很遗憾,我的评论没有得到答复。该答案假定问题是使用普通默认路由而不是具有子域的路由。
示例:
用户正在访问 sub.website.com 但 route() returns 网站。com/blabla 而不是 sub.website。com/blabla
您可以通过在 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'
]);
}
使用此方法会导致 route() 和控制器参数出现问题。
route()问题
在使用此方法的同时调用 route() 函数时,您将收到缺少参数的错误。 route() 函数需要您提供 {subdomain}.{domain}.{tld} 参数。
您可以通过创建自己的路由函数来解决这个问题。我将其命名为 mdroute()(多域路由)。
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);
}
控制器问题
参数 {sub}.{domain}.{tld} 总是发送到您的控制器。您不能像以前那样访问其他参数。
示例:
// 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'
}
您可以通过请求对象访问您的参数来解决这个问题。
public function getIndex(Request $request)
{
$id = $request->id;
$param2 = $reqeust->param2;
}