Использование относительного пути для вызова службы в AngularJS
У меня есть следующий код, который работал нормально до тех пор, пока я не развернулся на тестовом сервере:
$scope.getUserList = function (userName) {
$http({
method: "get",
url: "GetUserList",
params: { userName: userName }
}).
success(function (data) {
$scope.users = data;
}).
error(function () {
alert("Error getting users.");
Проблема заключается в том, что я развернулся в виртуальном каталоге, а вызов ниже пытается попасть в GetUserList из корня сервера. Это имеет смысл, и я знаю несколько способов исправить это.
То, что я хотел бы знать, - это правильный способ ссылки на URL-адрес службы таким образом, чтобы он был переносимым и поддерживаемым в Angular.
Ответы
Ответ 1
Я бы предложил использовать базовый тег HTML в голове и кодировать все пути относительно этого. Например, в ASP.NET вы можете получить ссылку на базу приложения, которая может быть или не быть корневым путем для сайта, поэтому полезно использовать базовый тег. Бонус: он работает и для всех других активов.
У вас может быть базовый путь следующим образом:
<base href="/application_root/" />
... и тогда ссылки типа "foo/bar.html" будут фактически /application _root/foo/bar.html.
Еще один подход, который мне нравится использовать, - это поместить именованные ссылки в заголовок. У меня часто будет корень API в одном месте и корень шаблона директивы где-то в другом месте. Вначале я добавлю следующие теги:
<link id="linkApiRoot" href="/application_root/api/"/>
<link id="linkTemplateRoot" href="/application_root/Content/Templates/"/>
... и затем используйте $provision в модуле, чтобы получить ссылку href и выставить ее на службы и директивы следующим образом:
angular.module("app.services", [])
.config(["$provide", function ($provide) {
$provide.value("apiRoot", $("#linkApiRoot").attr("href"));
}]);
... и затем добавьте его в сервис, подобный этому:
angular.module("app.services").factory("myAdminSvc", ["apiRoot", function (apiRoot) {
var apiAdminRoot = apiRoot + "admin/";
...
Просто мое мнение. Сделайте наименее сложную вещь для своего приложения.
Ответ 2
Я бы предложил определить модуль, который содержит глобальную конфигурацию, которую вы можете передать вокруг своего приложения:
// Module specific configuration
angular.module('app.config')
.value('app.config', {
basePath: '/' // Set your base path here
});
Затем вы можете получить доступ к этому из любого места вашего приложения благодаря инъекции зависимостей AngularJS:
// Make sure your config is included in your module
angular.module('app', ['app.config']);
// Access your config e.g. in a controller
angular.module('app')
.controller('TestCtrl', ['$scope','app.config', function($scope, config){
// Use config base path to assemble url
$scope.url = config.basePath + 'GetUserList';
...
}]);
При изменении базового пути (например, при переходе на другой сервер или хост) вам просто нужно изменить его в своей глобальной конфигурации, и все будет готово.
Ответ 3
Мне не удалось использовать тег <base>
, так как мое приложение было создано во всплывающем окне динамически из другого источника. Я рассматривал вариант others в этом потоке, чтобы использовать что-то вроде переменной basePath и использовать его в каждом $http, ng-src, templateUrl
и т.д.
Но это было немного накладно, построил перехватчик, который менял каждый url до того, как xhr был сделан
var app = angular.module("myApp", []);
app.config(["$httpProvider", function($httpProvider) {
$httpProvider.interceptors.push('middleware');
}]);
app.factory('middleware', function() {
return {
request: function(config) {
// need more controlling when there is more than 1 domain involved
config.url = "//example.com/api/" + config.url
return config;
}
};
});
app.controller("Ctrl", ["$http", function($http) {
$http.get("books"); // actually requestUrl = http://example.com/api/books
}])
И html а также
<div ng-include src="'view'">
<!-- actually src = http://example.com/api/view -->
</div>
Но я рекомендую использовать тег <base>
вместо этого, если вы не используете window.popup()
Ответ 4
Используйте службу определения местоположения $- она вернет ваш путь, хэш, адрес сервера. Все, что вам нужно! Ваш вызов будет $location.path()+"/GetUserList"
или что-то подобное.
Смотрите здесь: http://docs.angularjs.org/guide/dev_guide.services.$location
Ответ 5
Принятый ответ помог мне. Я использую Angular для моего приложения MVC.
Я сделал один дополнительный шаг, чтобы мой baseUrl мог использоваться в моих контроллерах Angular для вызовов веб-api или для доступа к шаблонам.
Использование ng-init для установки baseUrl (с заполненного значения на стороне сервера)
<html ng-app="app" ng-controller="AppController">
<head>
<base href="{{baseUrl}}" ng-init="baseUrl = '@Model.BaseUrl'" />
</head>
Angular контроллер
$scope.manageCustomerGroups = function () {
openDialog($scope.baseUrl + 'content/templates/customerGroups.html');
}
Ответ 6
У меня была аналогичная проблема
Я решаю его только с одной строкой кода на моей странице MVC
<base href="~/" />
Ответ 7
Простым способом я использую ASP.NET Razor (Web MVC), поэтому я получаю путь к программе и создаю ее как базу приложения.
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>Title</title>
<meta name="description" content="">
@{ var appPath = Request.ApplicationPath.ToString();
if (!appPath.EndsWith("/")) {
appPath = appPath + "/";
}
}
<base href="@appPath" />
Ответ 8
Я бы просто сделал все URL-адреса.
url: "../GetUserList",
вместо
url: "GetUserList",
Жесткое кодирование для дозы <base href="/application_root/" />
не является для меня хорошей идеей, так как вам может потребоваться изменить эту среду на окружающую среду и иметь зависимость от имени виртуального каталога.
Ответ 9
В функции ng-init передайте параметр, содержащий значение виртуального каталога (int ASP.NET, хранящегося в Request.ApplicationPath).
<div ng-controller="ControllerName" ng-init="init('@Request.ApplicationPath')">
Внутри контроллера angular используйте это значение в качестве префикса URL в каждом HTTP-вызове. Вы можете использовать эту функцию для объединения путей
function combinePath(path1, path2) {
if (path1 == null) {
return path2;
}
var last = path1.slice(-1);
var first = path2.charAt(0);
if (last == '/' && first == '/') {
path1 = path1.substring(0, path1.length - 1);
}
return path1 + path2;
}