Приложение Angular 8, развернутое на nginx в докере - GET, PUT, POST, PATCH не работает

Приложение Angular, развернутое в nginx на докере, не подключается к API-интерфейсу java. Метод GET возвращает html вместо объекта, POST, PUT, PATCH имеет 405 Not Allowed

У меня есть рабочее приложение angular * с backend api (загрузка java spring). Angular-приложение, работающее в среде IDE, уже настроило proxy.conf.json и работает с Chrome cors, передавая любой запрос бэкэнду. Проблема началась, когда я развернул приложение angular на nginx (пробовал 1.15.0, 1.16.0, 1.17.0) в докере. Ни одна из операций http.client работать не хочет. GET возвращает http-код вместо json / javascript-объекта. POST, PATCH, PUT возвращает 405 Not allowed.

Похоже, что проблема связана с неподходящей конфигурацией nginx, но, с другой стороны, я протестировал множество конфигураций обратного прокси и cors с тем же результатом ...

Приложение Angular: http://localhost:8100 (запускается из докера) Spring boot api: http://localhost:8081 (работает из IDE)

угловая сборка с помощью команды:

ng build --prod

dockerfile:

FROM nginx:1.17.0

COPY nginx.conf /etc/nginx/nginx.conf
COPY prm-web-app/ usr/share/nginx/html/

EXPOSE 8100

nginx.conf:

http {
    include       mime.types;
    default_type  application/json;
    sendfile        on;
    keepalive_timeout  65;

    upstream api_server {
        server localhost:8081;
    }

    server {
        listen       8100;
        server_name example;
        index index.html index.htm;
        root /usr/share/nginx/html;

        location / {
          add_header Allow 'GET, POST, PUT, PATCH, DELETE' always;
          add_header 'Access-Control-Allow-Origin' '*' always;
          add_header 'Access-Control-Allow-Methods' 'GET, PUT, POST, PATCH, DELETE, OPTIONS' always;
          add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range' always;
          add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range' always;
          add_header 'Access-Control-Allow-Credentials' 'true' always;

          try_files $uri $uri/ /index.html;
        }

        location /api {
            add_header Allow 'GET, POST, PUT, PATCH, DELETE' always;
            proxy_pass http://api_server;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-NginX-Proxy true;
            proxy_redirect off;
            proxy_set_header Host $http_host;
        }

        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }        
    }
}

угловые дополнения для примеров:

private extractData(res: Response) {
    const body = res;
    return body || { };
  }
private httpHeaders = new HttpHeaders({
    'Content-Type': 'application/json',
    'Access-Control-Allow-Origin': '*',
    'Access-Control-Allow-Headers': 'Origin, X-Request-With, Content-type, Accept, X-Access-Token',
    'Access-Control-Allow-Methods': 'GET, POST, PUT, PATCH, OPTIONS'
  });

angular пример операции GET:

getAppointment(id: string): Observable<any> {
    return this.http.get(apiEndpoint + '/' + id).pipe(
      map(this.extractData),
      catchError( err => {
        this.logger.logError(ErrorLevel.ERROR, JSON.stringify(err));
        err = this.handleError(err);
        return throwError(err);
      })
    );

angular пример операции POST:

postSearchTimeSlot(searchTimeSlotPostRequest: SearchTimeSlotPostRequest): Observable<any> {
    const options = {headers: this.httpHeaders};
    return this.http.post(searchTimeSlotEndpoint + '/', searchTimeSlotPostRequest, options).pipe(
      map(this.extractData),
      catchError(err => {
        this.logger.logError(ErrorLevel.ERROR, JSON.stringify(err));
        err = this.handleError(err);
        return throwError(err);
      })
    );
  }

Я пробовал такие решения, как:

error_page 405 =200 $uri;

а также:

error_page 405 = @app;

location @app {
proxy_pass http://localhost:8081/api;
}

и: добавлено приложение / json в mime.types и:

const options = {headers: this.httpHeaders, responseType: 'json' as 'json'};
const options = {headers: this.httpHeaders, responseType: 'text' as 'json'};

а также:

@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {

@Bean
    public WebMvcConfigurer corsConfigurer(){
        return new WebMvcConfigurer() {
            @Override
            public void addCorsMappings(CorsRegistry registry) {
                registry.addMapping("/**")
                        .allowedMethods("PUT", "POST", "PATCH", "GET")
                        .allowCredentials(true).maxAge(3600);
            }
        };
    }


    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**");
    }
}

и несколько других с proxy_pass и add_header для nginx. Сейчас уже идей не хватает ...

Каждый раз возникают одни и те же проблемы (проверено на последних версиях chrome и mozilla firefox): для запроса GET:

{
"headers": {
"normalizedNames": {},
"lazyUpdate": null
},
"status": 200,
"statusText": "OK",
"url": "http://localhost:8100/appointment_api/api/v1/appointment/123412341234",
"ok": false,
"name": "HttpErrorResponse",
"message": "Http failure during parsing for http://localhost:8100/appointment_api/api/v1/appointment/123412341234",
"error": {
"error": {},
"text": "<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>Example</title>
  <base href="/">

  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="icon" type="image/x-icon" href="favicon.ico">
<link rel="stylesheet" href="styles.ab8e79b2d91e978b1e50.css"></head>
<body>
    <app-root></app-root>
<script src="runtime-es2015.858f8dd898b75fe86926.js" type="module"></script><script src="polyfills-es2015.b8312458afdf3a7f4969.js" type="module"></script><script src="runtime-es5.741402d1d47331ce975c.js" nomodule></script><script src="polyfills-es5.8de8aa8baf008bce96d4.js" nomodule></script><script src="scripts.99edbfa41b8b40270fe5.js"></script><script src="main-es2015.49e5dbe84808fb269a5d.js" type="module"></script><script src="main-es5.628bd9db49e6b16c7a86.js" nomodule></script></body>
</html>
"
}
}

приведенный выше код ошибки в браузере связан с тем, что angular по умолчанию ожидает json, но nginx возвращает html instad json.

для запроса PUT, POST, PATCH:

"status": 405,
"statusText": "Not Allowed",
"url": "http://localhost:8100/appointment_api/api/v1/searchTimeSlot/",
"ok": false,
"name": "HttpErrorResponse",
"message": "Http failure response for http://localhost:8100/appointment_api/api/v1/searchTimeSlot/: 405 Not Allowed",
"error": "<html>
<head><title>405 Not Allowed</title></head>
<body>
<center><h1>405 Not Allowed</h1></center>
<hr><center>nginx/1.17.0</center>
</body>
</html>

По обеим вопросам не знаю, что виноват и как это исправить.


person PatrickEOD    schedule 30.07.2019    source источник
comment
Что будет localhost 8081 внутри контейнера?   -  person jonrsharpe    schedule 30.07.2019
comment
Нет, java api под localhost: 8081 запускается непосредственно из intellij Idea. Позже я хочу докерировать все api, но пока попробую небольшие шаги   -  person PatrickEOD    schedule 30.07.2019


Ответы (1)


Задача решена.

Это был докер, который блокировал трафик от nginx к API - (я тестировал dockerized angular на nginx, но api запускались непосредственно из IDE.

Решением было создать docker compose, который объединит все необходимые модули (api и front-end) в одну сеть докеров или (как я это сделал) развернул непосредственно на кубернетах и ​​настроил сервисы.

person PatrickEOD    schedule 07.08.2019