Angular 2/4/5-동적으로 기본 href 설정


131

클라이언트에 Angular 2를 사용하는 엔터프라이즈 앱이 있습니다. 고객마다 고유 한 URL (예 : https://our.app.com/customer-one및)이 https://our.app.com/customer-two있습니다. 현재 우리 <base href...>는를 사용 하여 동적으로 설정할 수 document.location있습니다. 사용자 안타 그래서 https://our.app.com/customer-two<base href...>설정됩니다 /customer-two... 딱!

문제는 사용자가 예를 들어 https://our.app.com/customer-two/another-page페이지를 새로 고치거나 해당 URL을 직접 입력하려고 <base href...>하면로 설정되고 /customer-two/another-page리소스를 찾을 수 없다는 것입니다.

다음은 아무 소용이 없습니다.

<!doctype html>
<html>

<head>
  <script type='text/javascript'>
    var base = document.location.pathname.split('/')[1];
    document.write('<base href="https://stackoverflow.com/' + base + '" />');
  </script>

...

불행히도 우리는 아이디어가 새롭습니다. 어떤 도움이라도 놀랄 것입니다.


1
APP_BASE_HREF로 시도한 적이 있습니까? 나는 확신이 구현 될 얼마나 아니지만, ... 유용 할 무언가를 것 같다
Jarod 모저

물론 현재 사용중인 라우터 버전에 따라 다릅니다. 라우터 버전 3.0.0-alpha.x를 사용하고 있습니까?
Jarod 모저

저는 "@ angular / router"를 사용하고 있습니다 : "3.0.0-alpha.7"
sharpmachine

5
Angular 7-2018 년 11 월. 이것은 여전히 ​​문제입니다. 현재 답변은 부분적인 해결책을 제공합니다. 앵귤러 모듈 내부에서 작업하는 것은 너무 늦습니다. 색인 HTML이 제공 될 때 스크립트를 가져올 위치를 알아야합니다. 내가 보는 방식은 두 가지뿐입니다-asp \ php \ whatever를 사용하여 동적 basehref 콘텐츠로 index.html을 제공합니다. 또는 index.html 파일에서 네이티브 자바 스크립트를 사용하여 DOM 콘텐츠가 각도에 도달하기 전에 변경합니다. 둘 다 일반적인 문제에 대한 잘못된 해결책입니다. 슬퍼.
Stavm

1
누군가 내 질문에 대답 해 주시겠습니까? stackoverflow.com/questions/53757931/…
Karan

답변:


166

여기에 표시된 답변으로는 내 문제가 해결되지 않았으며 다른 각도 버전 일 수 있습니다. angular cli터미널 / 셸에서 다음 명령을 사용하여 원하는 결과를 얻을 수있었습니다 .

ng build --base-href /myUrl/

ng build --bh /myUrl/ 또는 ng build --prod --bh /myUrl/

이것은 변경 <base href="https://stackoverflow.com/"><base href="https://stackoverflow.com/myUrl/">에서 유일한 내장 버전 개발과 생산 사이의 환경에서 우리의 변화에 대한 완벽했다. 가장 좋은 점은이 방법을 사용하여 코드베이스를 변경할 필요가 없다는 것입니다.


요약하려면 index.html기본 href를 <base href="https://stackoverflow.com/">다음 ng build --bh ./과 같이 두십시오 . 그런 다음 angular cli로 실행 하여 상대 경로로 만들거나 ./필요한 것으로 대체하십시오 .


최신 정보:

위의 예에서 명령 줄에서 수행하는 방법을 보여 주듯이 angular.json 구성 파일에 추가하는 방법은 다음과 같습니다.

이것은 모두 ng serving지역 개발을 위해 사용될 것입니다

"architect": {
    "build": {
      "builder": "@angular-devkit/build-angular:browser",
      "options": {
        "baseHref": "/testurl/",

이것은 prod와 같은 구성 빌드에 특정한 구성입니다.

"configurations": {
   "Prod": {
     "fileReplacements": [
        {
          "replace": src/environments/environment.ts",
          "with": src/environments/environment.prod.ts"
        }
      ],
      "baseHref": "./productionurl/",

사용법에 관한 공식 angular-cli 문서.


35
이 솔루션에는 고객 별 빌드가 필요하며 이는 OP의 문제를 해결하지 못할 수 있습니다.
Maxime Morin

1
지금까지 내 경험에서 @MaximeMorin은 ./모든 위치 에서 작동합니다. 그래서 실제로 저는 당신이 클라이언트별로 빌드 할 필요가 없다고 생각합니다.
Zze

9
@Zze 제 경험 ./은 매우 달랐습니다. 사용자가 경로를 탐색하고 브라우저의 새로 고침 버튼 또는 키를 누를 때까지 작동합니다. 이 시점에서 재 작성은 호출을 처리하고 인덱스 페이지를 제공하지만 브라우저는 ./웹 앱의 루트 폴더가 아닌 현재 경로 라고 가정 합니다. 기본 href를 설정하는 동적 (.aspx, .php, .jsp 등) 인덱스로 OP의 문제를 해결했습니다.
Maxime Morin

2
--prod빌드 중에 사용 base href한다고해서 가치가 변경 되지는 않습니다. 여기서 이야기하지 마세요. --prodangular-cli사용하는 environment.prod.ts기본 파일 대신 파일을 environment.ts사용자의 environments폴더
매튜 이언

1
@MattewEon --prodOP에서 배포에 대해 이야기하고 있었기 때문에 플래그 와 호환된다는 것을 보여주었습니다 .
Zze

57

여기에 우리가 한 일이 있습니다.

이것을 index.html에 추가하십시오. <head>섹션 에서 가장 먼저해야합니다.

<base href="https://stackoverflow.com/">
<script>
  (function() {
    window['_app_base'] = '/' + window.location.pathname.split('/')[1];
  })();
</script>

그런 다음 app.module.ts파일 에서 다음 { provide: APP_BASE_HREF, useValue: window['_app_base'] || '/' }과 같이 공급자 목록에 추가 합니다.

import { NgModule, enableProdMode, provide } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { APP_BASE_HREF, Location } from '@angular/common';


import { AppComponent, routing, appRoutingProviders, environment } from './';

if (environment.production) {
  enableProdMode();
}

@NgModule({
  declarations: [AppComponent],
  imports: [
    BrowserModule,
    HttpModule,
    routing],
  bootstrap: [AppComponent],
  providers: [
    appRoutingProviders,
    { provide: APP_BASE_HREF, useValue: window['_app_base'] || '/' },
  ]
})
export class AppModule { }

오류 TS7017 : '창'유형에 색인 서명이 없기 때문에 요소에 암시 적으로 '임의'유형이 있습니다. useValue: (window as any) ['_app_base'] || '/'도움
Erkan Buelbuel

최신 ng2에서 실제로 작동하지 않습니다. 해결책이 있습니까? (잘못된 스크립트 경로를로드 한 다음 좋은 스크립트 경로를로드하지만 모바일에서는로드하지 않음)
Amit

1
내용 길이가 댓글을 달기에 너무 길기 때문에 아래 답변으로 추가하십시오.
Krishnan

1
@Amit 최신 ng2에서 쉽게 해결하려면 아래 내 대답을 참조하십시오.
Zze

3
다른 파일의 문제를 어떻게 해결 했습니까? 내 브라우저가 localhost : 8080 / main.bundle.js 를로드하려고하는데 contextPath가 다르기 때문에 로드 할 수 없습니까? ( localhost : 8080 / hello / main.bundle.js를 가져와야합니다. )
Sasa

33

귀하의 (@sharpmachine) 답변을 바탕으로 조금 더 리팩토링 할 수 있었으므로 .NET에서 함수를 해킹 할 필요가 없습니다 index.html.

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { APP_BASE_HREF, Location } from '@angular/common';

import { AppComponent } from './';
import { getBaseLocation } from './shared/common-functions.util';

@NgModule({
  declarations: [AppComponent],
  imports: [
    BrowserModule,
    HttpModule,
  ],
  bootstrap: [AppComponent],
  providers: [
    appRoutingProviders,
    {
        provide: APP_BASE_HREF,
        useFactory: getBaseLocation
    },
  ]
})
export class AppModule { }

그리고 다음을 ./shared/common-functions.util.ts포함합니다.

export function getBaseLocation() {
    let paths: string[] = location.pathname.split('/').splice(1, 1);
    let basePath: string = (paths && paths[0]) || 'my-account'; // Default: my-account
    return '/' + basePath;
}

1
myapp이 하위 폴더에 배포되었습니다. 이제 내 URL은 다음과 같습니다. http://localhost:8080/subfolder/myapp/#/subfolder/myroute이것이 귀하의 URL 입니까? # 다음의 하위 폴더를 제거하는 방법을 알고 http://localhost:8080/subfolder/myapp/#/myroute있습니까?
techguy2000

오. href 기반은 LocationStrategy에만 필요하다고 생각합니다. 제 경우에는 HashLocationStrategy를 사용하고 있습니다. 그래서 나는 그것을 설정할 필요조차 없습니다. LocationStrategy로 새로 고침을 처리하는 특수 코드를 작성 했습니까?
techguy2000

1
예, AFAIK base href에만 필요합니다 LocationStrategy. LocationStrategy로 새로 고침을 처리하는 특수 코드를 작성하려면 정확히 무엇을 의미하는지 확실하지 않습니다. 내 앱에서 활동하는 동안 내 "기본 href"가 변경되면 어떻게하나요? 그 다음, 예, window.location.href = '/' + newBaseHref;변경해야하는 곳 과 같은 더러운 일을해야했습니다 . 너무 자랑스럽지 않습니다. 또한 업데이트를 제공하기 위해 내 앱에서 이러한 해킹 솔루션이 디자인 문제가되면서 멀어졌습니다. 라우터 매개 변수는 완벽하게 잘 작동하므로 이에 충실했습니다.
Krishnan

1
당신은 appRoutingProvider어떻게 생겼나요, 크리슈 난? 나는 받아 들여진 대답이 동일하게 사용되는 것을 봅니다. 방금 복사 한 것일 수도 providers있지만 그렇지 않은 경우 샘플을 제공하거나 용도를 설명해 주시겠습니까? 그만큼에만 문서 imports모듈을 라우팅는 , 그것 (내가 볼 수있는만큼 지금까지) 어떤 라우팅 관련 공급자를 사용하지 않습니다
레드 완두콩

: @Krishnan 여기에 나는 그것이 작동하도록 nginx를 함께해야 할 것입니다location /subfolder/myapp/ { try_files $uri /subfolder/myapp/index.html; } location /subfolder2/myapp/ { try_files $uri /subfolder2/myapp/index.html; }
techguy2000

24

./동일한 도메인에서 여러 앱을 빌드 할 때 현재 작업 디렉토리를 사용 합니다.

<base href="./">

참고 .htaccess로 페이지 새로 고침시 라우팅을 지원하기 위해 사용 합니다.

RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule .* index.html [L]

2
에 대해 정말 감사 .htaccess파일
Shahriar 시라즈 Snigdho에게

8
이 대답은 틀 렸으며 / your-app / a / b / c와 같은 경로에서는 작동하지 않습니다. 이러한 경로에서 페이지를 새로 고치면 Angular는 / your-app / a / b /에서 런타임, 폴리 필 및 기본 JS 파일과 스타일 CSS 파일을 찾습니다. 그들은 분명히 그 위치에 있지 않지만 / your-app / 아래에 있습니다
toongeorges

2
@toongeorges이 답변은 페이지 재로드시 라우팅을 처리하기 위해 Apache Web Server 소프트웨어가 감지하고 실행하는 구성 파일을 사용하여 거의 2 년 전에 작성되었습니다. 이 솔루션이 올바르지 않고 작동하지 않는다고 말하는 것은 오해의 소지가 있지만 구성과 함께 작동하도록하는 방법을 알 수 없다는 의미입니다.
Daerik

나는 아파치 재 작성 규칙을 간과했고 이것이 아파치에서 작동하지 않을 것이라고 말할만큼 충분히 알지 못하므로 내가 틀렸을 수 있으며 귀하의 대답이 정확할 수 있습니다. 어쨌든 나는 여기에 여러 답변이 주어 졌기 때문에 서버 구성을 수정할 필요가없는 솔루션을 선호합니다. 이것은 응용 프로그램을 다른 서버에서 이식 가능하게 만들기 때문입니다.
toongeorges 18:41에

2
아니, @toongeorges가 맞고,로 변경하는 <base href="./">것은 잘못되었으며 /app/a/b/c실제로 와 같은 경로 를 망칠 것입니다. 웹 앱만 다루는 경우 기본 href 설정을 선호하거나 배포시 기본 href를 변경하는 각도 방식을 살펴보십시오 (여기에 언급 된 많은 답변이 있습니다).
giovannipds

15

@sharpmachine에 의한 기존 답변의 단순화 .

import { APP_BASE_HREF } from '@angular/common';
import { NgModule } from '@angular/core';

@NgModule({
    providers: [
        {
            provide: APP_BASE_HREF,
            useValue: '/' + (window.location.pathname.split('/')[1] || '')
        }
    ]
})

export class AppModule { }

APP_BASE_HREF 불투명 토큰에 대한 값을 제공하는 경우 index.html에서 기본 태그를 지정할 필요가 없습니다.


10

이것은 prod 환경에서 잘 작동합니다.

<base href="https://stackoverflow.com/" id="baseHref">
<script>
  (function() {
    document.getElementById('baseHref').href = '/' + window.location.pathname.split('/')[1] + "/";
  })();
</script>

2
이 솔루션은 IIS의 다중 VD 설정에 큰 제한이 있습니다. 청크의 중복로드가 발생합니다.
Karan

9

angular4에서는 .angular-cli.json 앱에서 baseHref를 구성 할 수도 있습니다.

.angular-cli.json에서

{   ....
 "apps": [
        {
            "name": "myapp1"
            "baseHref" : "MY_APP_BASE_HREF_1"
         },
        {
            "name": "myapp2"
            "baseHref" : "MY_APP_BASE_HREF_2"
         },
    ],
}

index.html의 기본 href가 MY_APP_BASE_HREF_1로 업데이트됩니다.

ng build --app myapp1

4
또한 각 앱에 대한 빌드를 만들어야합니다.
Patrick Hillert

6

Angular CLI 6을 사용하는 경우 angular.json에서 deployUrl / baseHref 옵션을 사용할 수 있습니다 (프로젝트> xxx> 아키텍트> 빌드> 구성> 프로덕션). 이러한 방식으로 프로젝트별로 baseUrl을 쉽게 지정할 수 있습니다.

빌드 된 앱의 index.html을보고 설정이 올바른지 확인하십시오.


7
이를 위해서는 모든 의미와 함께 각 환경에 대해 다른 빌드가 필요합니다.
Stavm

3

추가 기능 : 원하는 경우 예 : 라우터의 애플리케이션 기반으로 / users 및 자산 사용의 기반으로 / public

$ ng build -prod --base-href /users --deploy-url /public

1

비슷한 문제가 있었지만 실제로 웹 내 일부 파일의 존재를 조사했습니다.

probePath 는 확인하려는 파일의 상대 URL (현재 올바른 위치에있는 경우 마커 종류)입니다. 예 : 'assets / images / thisImageAlwaysExists.png'

<script type='text/javascript'>
  function configExists(url) {
    var req = new XMLHttpRequest();
    req.open('GET', url, false); 
    req.send();
    return req.status==200;
  }

  var probePath = '...(some file that must exist)...';
  var origin = document.location.origin;
  var pathSegments = document.location.pathname.split('/');

  var basePath = '/'
  var configFound = false;
  for (var i = 0; i < pathSegments.length; i++) {
    var segment = pathSegments[i];
    if (segment.length > 0) {
      basePath = basePath + segment + '/';
    }
    var fullPath = origin + basePath + probePath;
    configFound = configExists(fullPath);
    if (configFound) {
      break;
    }
  }

  document.write("<base href='" + (configFound ? basePath : '/') + "' />");
</script>

-1

솔직히 말해서, 당신의 케이스는 저에게 잘 작동합니다!

Angular 5를 사용하고 있습니다.

<script type='text/javascript'>
    var base = window.location.href.substring(0, window.location.href.toLowerCase().indexOf('index.aspx'))
    document.write('<base href="' + base + '" />');
</script>

이 솔루션이 효과가 있습니까? 나는 문제에 직면하고있다. 내 게시물에도 답장 해 주시겠습니까? stackoverflow.com/questions/53757931/…
Karan

1
document.write () 사용을 피하십시오 : developers.google.com/web/updates/2016/08/…
Patrick Hillert

-6

방금 변경했습니다.

  <base href="/">

이에:

  <base href="/something.html/">

/로 끝나는 것을 잊지 마세요

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.