Использование относительного пути для вызова службы в 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;
}