Access-Control-Expose-Headers

Kr4n3oK

Hola chavales!.

Tengo un proyecto que trabajar en un marco CORS, y donde tengo problemas al obtener un header en concreto "Location". Cuando mediante el método POST mando un json para insertarlo y todo ha ido bien, el back me devuelve un header "Location" con la URL el ID del nuevo elemento insertado. Lo raro de todo esto es que no consigo leer dicha cabecera. Si entro al DevTools de Chrome la veo, sin embargo no consigo acceder a ella.

El FRONT está montado en Angular5 y estoy observando la respuesta para obtener junto al body, todas las cabeceras de respuesta, aunque solo puedo leer la Content-Type.

protected post(body, urlParams?): Observable<any> {
        return new Observable(
            (observer) => {
                this.http.post(this.URL + (urlParams ? urlParams : ''), body, {
                    headers: new HttpHeaders().append('Authorization', this._appConfig.getConfig('AUTH')[this._appConfig.getEnv('env')])
                    .append('Content-Type','application/json'),
                    
observe: 'response' }).subscribe( (result) => { observer.next(new ServiceResponse('endpoint', 201, 'CREATED', result)); }, (error) => { observer.next(this.getError(error)); } ); } ); }

¿Aguien se ha encontrado con el mismo problema?. Buscado por inet he visto que es algo que ocurre de forma común, y sin embargo, yo no he conseguido que funcione. He de decir que la aplicación se despliega en un docker con nginx y que modificando el fichero de nginx.conf no consigo que coja las configuraciones que le estoy metiendo, que son con la cabecera Access-Control-Expose-Header : <cabeceras a leer en front>

En fin, espero que alguien pueda arrojarme algo de luz.

Muchas gracias y saludos!

C1P073

Yo las cabeceras que metes a mano las metería con un interceptor, si vas a meterlas siempre que estés autenticado.

import { Injectable, Injector } from '@angular/core';
import { HttpEvent, HttpInterceptor, HttpHandler, HttpRequest } from '@angular/common/http';
import { SessionService } from './../session/session.service';
import { Observable } from 'rxjs/observable';
import 'rxjs/add/observable/throw';
import 'rxjs/add/operator/catch';

@Injectable()
export class SecureHttpInterceptor implements HttpInterceptor {

  constructor(private _session: SessionService) { }

  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {

// Clone the request to add the new header.
const headers: any = {
  'Content-Type': 'application/json'
};

if (this._session.hasSession()) {
  headers.sessionId = this._session.getSession().id;
}
const authReq = req.clone({ setHeaders: headers });

// send the newly created request
return next.handle(authReq)
  .catch((error, caught) => {
    // intercept the respons error and displace it to the console
    console.error('Error:', error);
    // return the error to the method that called it
    return Observable.throw(error);
  }) as any;
  }
}

En app.module.ts...

...
// Http interceptor
import { HttpClientModule, HttpClient, HTTP_INTERCEPTORS } from '@angular/common/http';
...
import { SecureHttpInterceptor } from './shared/services/services.index';

@NgModule({
  ...
  providers: [
    { provide: HTTP_INTERCEPTORS, useClass: SecureHttpInterceptor, multi: true }
  ]
)};

Creo que haciendo algo así sacarías la header que quieres llamando a esta promesa...

post(body, urlParams): Promise<any> {
  return new Promise((resolve, reject) => {
    this.http.post(this.url + urlParams, body)
      .map(headerRes => headerRes.headers.get('Location'))
      .subscribe((res: string) => {
        resolve(res);
      }, (e) => {
        reject(e);
      });
  });
}

Entonces desde donde lo vayas a usar si está la función promesa en MyServices...

...
constructor(_ms: MyServices) {}

this._ms.post({...}, ...).then((location: string) => {
  new ServiceResponse('endpoint', 201, 'CREATED', location)
}, (error) => {
  this.getError(error);
});
1 respuesta
Kr4n3oK

#2 Hola buenos días, gracias por tu respuesta.

Esta pregunta vas mas orientada a configuración de servidor nginx, ya que con angular para obtener todas las cabeceras de respuesta se usa el parámetro observe:response, donde debería estar el Location y de hecho está es accesible en entornos no CORS. Como ya hemos desplegado en producción y trabajamos en un marco CORS hay que definir que cabeceras de respuesta son leíbles desde el navegador y eso se hace usando el access-control-expose-headers, pero ni con esas...

Gracias de todos modos y muchos saludos!

PiPePiTo

Si en el chrome te aparecen es que el back end las está enviando, no?

sh31k

Que cabeceras tienes en el nginx.conf ?

Y en que lenguaje tienes montada la API ?

Kr4n3oK

Ya hemos solucionado el problema. Estamos usando WSO2, lo que interceptas las request antes de enviarlas al servidor real, y si no se especifica en su fichero correspondiente las cabeceras disponibles, solo deja las de por defecto, que son unas 6.

Gracias y saludos!

Usuarios habituales

  • Kr4n3oK
  • sh31k
  • PiPePiTo
  • C1P073