Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

  1. #1
    Nouveau membre du Club
    Homme Profil pro
    Développeur informatique
    Inscrit en
    juin 2012
    Messages
    40
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : juin 2012
    Messages : 40
    Points : 36
    Points
    36

    Par défaut Erreur cross origin : Uncaught (in promise): HttpErrorResponse - No 'Access-Control-Allow-Origin' header

    Bonjour,

    je développe une appli de gestion de produits sur angular 6 et spring boot 2.

    J'ai créé mon service qui appelle la liste de mes produits côté angular et côté spring boot le contrôleur associé avec l'annotation cross origin pour permettre mon front d'atteindre mon back.

    Malheureusement , quand je tape l'url : http://localhost:4200/produit, j'ai une erreur sur la console de mon navigateur : chrome, firefox, safari :

    Error: Uncaught (in promise): HttpErrorResponse: {"headers":{"normalizedNames":{},"lazyUpdate":null,"headers":{}},"status":0,"statusText":"Unknown Error","url":null,"ok":false,"name":"HttpErrorResponse","message":"Http failure response for (unknown url): 0 Unknown Error","error":{"isTrusted":true}}
    at resolvePromise (zone.js:831)
    at resolvePromise (zone.js:788)


    voici mon service côté angular :
    Code js : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    export const API_URLS = {
        PRODUITS_URLS : 'http://localhost:8080/api/produit'
    }

    Code js : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    import { Injectable } from "@angular/core";
    import { HttpClient, HttpHeaders } from "@angular/common/http";
    import { Observable } from "rxjs";
     
    import { API_URLS } from '../config/api.url.config';
    import { Produit } from "../shared/produit";
     
    const httpOptions = {
        headers: new HttpHeaders({ 'Content-Type': 'application/json' })
      };
     
    @Injectable()
    export class ProduitService {
     
        constructor(private http : HttpClient) {
     
        }
     
        getPoduits():Observable<any>{
            /*return this.http.get(API_URLS.PRODUITS_URLS);*/
            return this.http.get('/api/produit');
        }
     
        addProduit(produit : Produit):Observable<any>{
            return this.http.post('/api/produit',produit);
        }
     
        updateProduit(produit : Produit):Observable<any>{
            /*return this.http.put(API_URLS.PRODUITS_URLS,produit);*/
            return this.http.put('/api/produit',produit);
        }
     
        deleteProduit(id : number):Observable<any>{
            return this.http.delete(`/api/produit/${id}`);
        }
    }

    Code js : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    import { Component, OnInit } from '@angular/core';
    import { Produit } from '../shared/produit';
    import { FormGroup, FormBuilder, Validators } from '@angular/forms';
    import { ProduitService } from './produit.service';
    import { ActivatedRoute } from '@angular/router';
     
    @Component({
      selector: 'app-produit',
      templateUrl: './produit.component.html',
      styleUrls: ['./produit.component.css']
    })
    export class ProduitComponent  implements OnInit {
     
      produitForm : FormGroup;
     
      products:Produit[];
     
      operation : string = 'add';
     
      selectedProduit : Produit;
     
      constructor(private produitService:ProduitService, private fb : FormBuilder,
        private route : ActivatedRoute) {
        this.createForm();
      }
     
      ngOnInit() {
        /*this.products = this.produitService.getPoduits();*/
        this.initProduit();
       // this.loadProduits();
        this.products = this.route.snapshot.data.produits;
      }
     
      createForm(){
        this.produitForm = this.fb.group({
          ref:['', Validators.required],
          quantite:'',
          prixUnitaire:''
        });
      }
     
      loadProduits() {
        this.produitService.getPoduits().subscribe(
          data => { this.products = data},
          error => { console.log("An error was occured.")},
          () => { console.log("loading products")}
        )
      }
     
      addProduit(){
        const p = this.produitForm.value;
        console.log("produit envoye ");
        console.log(p);
        this.produitService.addProduit(p).subscribe(
          res => {
            this.initProduit();
            this.loadProduits();
          }
        );
      }
     
      updateProduit(){
        this.produitService.updateProduit(this.selectedProduit).subscribe(
          res => {
            this.initProduit();
            this.loadProduits();
          }
        );
      }
     
      initProduit(){
        this.selectedProduit =  new Produit();
        this.createForm();
      }
     
      deleteProduit(){
        this.produitService.deleteProduit(this.selectedProduit.id).subscribe(
          res => {
            this.loadProduits();
          }
        );
      }
     
     
    }

    Code HTML : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    <!-- <h3>Hello produits</h3>
    <ul >
        <li *ngFor="let product of products">
            Ref : {{product.ref}}
            Quantité : {{product.quantite}}
            Prix unitaire : {{product.prixUnitaire}}
        </li>
    </ul> -->
    <h3>Produits</h3>
    <div class="container">
        <div class="row">
            <div class="col-lg-7">
                <table class="table table-hover">
                    <thead>
                        <tr>
                            <th>Référence</th>
                            <th>Quantité</th>
                            <th>Prix Unitaire</th>
                            <th><button class="btn btn-outlet-primary"
                                    (click)="operation = 'add';initProduit();">ADD</button></th>
                        </tr>
                    </thead>
                    <tbody>
                        <tr *ngFor="let produit of products">
                            <td>{{produit.ref}}</td>
                            <td>{{produit.quantite}}</td>
                            <td>{{produit.prixUnitaire}}</td>
                            <td><button class="btn btn-outlet-primary"
                                    (click)="operation = 'edit'; selectedProduit = produit">Edit</button></td>
                            <td><button class="btn btn-outlet-danger" (click)="operation = 'remove'; selectedProduit = produit">Remove</button></td>
                        </tr>
                    </tbody>
                </table>
            </div>
            <div class="col-lg-5">
                <div class="card">
                    <div class="card-header bg-info text-white">
                        {{operation == 'add' ? 'Ajouter produit':
                        operation == 'edit' ? 'Modifier produit':
                        operation == 'remove' ? 'Supprimer produit':''}}
                    </div>
                    <div class="card-body">
                        <div *ngIf="operation == 'add' || operation == 'edit'">
                            <form [formGroup]="produitForm">
                                <div class="form-group">
                                    <label>Réference : </label>
                                    <input type="text" class="form-control" formControlName="ref"
                                        [(ngModel)]="selectedProduit.ref" />
                                </div>
                                <div class="alert alert-danger" *ngIf="produitForm.controls['ref'].invalid && 
                                        (produitForm.controls['ref'].dirty || produitForm.controls['ref'].touched)">
                                    Réference est obligatoire !
                                </div>
                                <div class="form-group">
                                    <label>Quantité : </label>
                                    <input type="number" class="form-control" formControlName="quantite"
                                        [(ngModel)]="selectedProduit.quantite" />
                                </div>
                                <div class="form-group">
                                    <label>Prix unitaire : </label>
                                    <input type="number" class="form-control" formControlName="prixUnitaire"
                                        [(ngModel)]="selectedProduit.prixUnitaire" />
                                </div>
                                <button class="btn btn-success"
                                    (click)="operation == 'add' ? addProduit() : updateProduit()"
                                    [disabled]="(produitForm.prestine || produitForm.invalid)">
                                    {{operation == 'add' ? 'Ajouter' : operation == 'edit' ? 'Modifier' : ''}}</button>
                            </form>
                        </div>
                        <div *ngIf="operation == 'remove'">
                            <p class="card-title">Réference : {{selectedProduit.ref}}</p>
                            <p class="card-title">Voulez-vous supprimer ce produit ?</p>
                            <button class="btn btn-success" [disabled]="!selectedProduit.ref" (click)="deleteProduit()">Confirmez</button>
                        </div>
     
                    </div>
                    <div class="card-footer">
     
                    </div>
                </div>
            </div>
        </div>
    </div>

    Code js : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    import { NgModule } from '@angular/core';
    import { RouterModule, Routes } from '@angular/router';
    import { ProduitComponent } from './produit/produit.component';
    import { DashboardComponent } from './dashboard/dashboard.component';
    import { ProduitResolver } from './produit/produit.resolver';
     
    export const appRoutes : Routes = [
        {
            path:'produit',
            component:ProduitComponent,
            resolve:{
                produits : ProduitResolver    
            }
        },
        {
            path:'dashboard',
            component:DashboardComponent
        },
        {
            path:'',
            redirectTo:'/dashboard',
            pathMatch:'full'
     
        }
    ]
     
    @NgModule({
        imports : [
            RouterModule.forRoot(
                appRoutes,
                {enableTracing:true}
            )
        ],
        exports : [RouterModule],
        providers : [ProduitResolver]
    })
     
    export class AppRoutingModule {
     
    }


    Code js : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    import { Injectable } from "@angular/core";
    import { Resolve } from "@angular/router";
    import { ProduitService } from "./produit.service";
     
    @Injectable()
    export class ProduitResolver implements Resolve<any> {
     
        constructor(private produitService : ProduitService) {
     
        }
     
        resolve() {
            return this.produitService.getPoduits();
        }
    }


    Code JSON : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    {
      "name": "gestion-stock",
      "version": "0.0.0",
      "scripts": {
        "ng": "ng",
        "start": "ng serve --proxy-config proxy.conf.json",
        "build": "ng build",
        "test": "ng test",
        "lint": "ng lint",
        "e2e": "ng e2e"
      },
      "private": true,
      "dependencies": {
        "@angular/animations": "^6.1.0",
        "@angular/common": "^6.1.0",
        "@angular/compiler": "^6.1.0",
        "@angular/core": "^6.1.0",
        "@angular/forms": "^6.1.0",
        "@angular/http": "^6.1.0",
        "@angular/platform-browser": "^6.1.0",
        "@angular/platform-browser-dynamic": "^6.1.0",
        "@angular/router": "^6.1.0",
        "core-js": "^2.5.4",
        "rxjs": "~6.2.0",
        "zone.js": "~0.8.26",
        "bootstrap": "^4.0.0-beta",
        "font-awesome": "^4.7.0",
        "jquery": "^3.2.1",
        "popper.js": "^1.12.5"
      },
      "devDependencies": {
        "@angular-devkit/build-angular": "~0.8.0",
        "@angular/cli": "~6.2.5",
        "@angular/compiler-cli": "^7.2.5",
        "@angular/language-service": "^6.1.0",
        "@types/jasmine": "~2.8.8",
        "@types/jasminewd2": "~2.0.3",
        "@types/node": "~8.9.4",
        "codelyzer": "~4.3.0",
        "jasmine-core": "~2.99.1",
        "jasmine-spec-reporter": "~4.2.1",
        "karma": "^4.0.0",
        "karma-chrome-launcher": "~2.2.0",
        "karma-coverage-istanbul-reporter": "~2.0.1",
        "karma-jasmine": "~1.1.2",
        "karma-jasmine-html-reporter": "^0.2.2",
        "protractor": "~5.4.0",
        "ts-node": "~7.0.0",
        "tslint": "~5.11.0",
        "typescript": "~3.1.1"
      }
    }

    et côté back end : java spring boot 2

    Code Java : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    package com.gestion.stock.controller;
     
    import java.util.List;
     
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.CrossOrigin;
    import org.springframework.web.bind.annotation.DeleteMapping;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.PathVariable;
    import org.springframework.web.bind.annotation.PostMapping;
    import org.springframework.web.bind.annotation.PutMapping;
    import org.springframework.web.bind.annotation.RequestBody;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
     
    import com.gestion.stock.entity.Produit;
    import com.gestion.stock.service.IProduitService;
     
    @RestController
    @RequestMapping("/api/produit")
    //@CrossOrigin
    @CrossOrigin(origins = "http://localhost:4200")
    public class ProduitController {
    	@Autowired
    	private IProduitService produitService;
     
    	@GetMapping
    	public List<Produit> getProduits() {
    		return produitService.getProduits();
    	}
     
    	@PostMapping
    	public void addProduit(@RequestBody Produit produit) {
    		produitService.addProduit(produit);
    	}
     
    	@PutMapping
    	public void updateProduit(@RequestBody Produit produit) {
    		produitService.updateProduit(produit);
    	}
     
    	@DeleteMapping("{/id}")
    	public void deletedProduit(@PathVariable Long id) {
    		produitService.deleteProduit(id);
    	}
    }


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    spring.jpa.hibernate.ddl-auto=create
    spring.datasource.url=jdbc:mysql://localhost:3306/stock_produits?zeroDateTimeBehavior=CONVERT_TO_NULL&serverTimezone=UTC
    spring.datasource.username=root
    spring.datasource.password=root
    je n'arrive pas à trouver la solution après multiple recherche sur le net.

  2. #2
    Membre expert

    Homme Profil pro
    Informagicien ès Java
    Inscrit en
    janvier 2004
    Messages
    2 297
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Suisse

    Informations professionnelles :
    Activité : Informagicien ès Java
    Secteur : Finance

    Informations forums :
    Inscription : janvier 2004
    Messages : 2 297
    Points : 3 641
    Points
    3 641

    Par défaut

    Le service appelé ne fournit pas d'header "Access-Control-Allow-Origin".

    C'est un header servant à gérer la liste des services autorisés par la page web (le serveur indique que la page est autorisée à invoquer des services se trouvant dans le domaine indiqué).

    Dans ton cas, certainement que le port n'est pas identique entre l'url de la page web et l'url du service appelé. Ce qui pose des soucis de sécurité (CORS -> Cross Origin Resource Sharing)

    Cf. https://developer.mozilla.org/en-US/...l-Allow-Origin
    "Le plug gros problème des citations trouvées sur internet, c'est qu'on ne peut jamais garantir leur authenticité"

    Confucius, 448 av. J-C

  3. #3
    Nouveau membre du Club
    Homme Profil pro
    Développeur informatique
    Inscrit en
    juin 2012
    Messages
    40
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : juin 2012
    Messages : 40
    Points : 36
    Points
    36

    Par défaut

    Bonjour et merci.

    ETant dans la configuration spring boot avec un repertoire pour mes entités, un repertoire pour mes services, un repertoire pour mes repository et un repertoir pour mes controleurs.

    Ma question est de savoir comment l'intégrer dans mon contrôleur via l'annotation @CrossOrigin

    Exemple :
    Code Java : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    package com.gestion.stock.controller;
     
    import java.util.List;
     
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.CrossOrigin;
    import org.springframework.web.bind.annotation.DeleteMapping;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.PathVariable;
    import org.springframework.web.bind.annotation.PostMapping;
    import org.springframework.web.bind.annotation.PutMapping;
    import org.springframework.web.bind.annotation.RequestBody;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
     
    import com.gestion.stock.entity.Produit;
    import com.gestion.stock.service.IProduitService;
     
    @RestController
    //@RequestMapping("/api/produit")
    //@CrossOrigin
    //@CrossOrigin(origins = "http://localhost:4200")
    @RequestMapping("/api")
    //@CrossOrigin("*")
    @CrossOrigin(origins = "http://localhost:4200", methods='POST, GET, PUT, OPTIONS, DELETE')
    public class ProduitController {
    	@Autowired
    	private IProduitService produitService;
     
    	// @GetMapping
    	@GetMapping("/produits")
    	public List<Produit> getProduits() {
    		return produitService.getProduits();
    	}
     
    	// @PostMapping
    	@PostMapping("/produit")
    	public void addProduit(@RequestBody Produit produit) {
    		produitService.addProduit(produit);
    	}
     
    	// @PutMapping
    	@PutMapping("/produit")
    	public void updateProduit(@RequestBody Produit produit) {
    		produitService.updateProduit(produit);
    	}
     
    	// @DeleteMapping("{/id}")
    	@DeleteMapping("/produit/{id}")
    	public void deletedProduit(@PathVariable("id") Long id) {
    		produitService.deleteProduit(id);
    	}
    }

    Dans la documentation spring, on en parle ici, mais je ne vois pas comment l'intégrer

    This @CrossOrigin annotation enables cross-origin requests only for this specific method. By default, its allows all origins, all headers, the HTTP methods specified in the @RequestMapping annotation and a maxAge of 30 minutes is used. You can customize this behavior by specifying the value of one of the annotation attributes: origins, methods, allowedHeaders, exposedHeaders, allowCredentials or maxAge.
    Quelque chose du style : @CrossOrigin(origins = "http://localhost:4200", maxAge = 3600)

  4. #4
    Expert éminent sénior
    Avatar de tchize_
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    avril 2007
    Messages
    25 461
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : Belgique

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : avril 2007
    Messages : 25 461
    Points : 48 730
    Points
    48 730

    Par défaut

    Il faudrait déjà voir un peu plus ce qui se passe au niveau de ton browser lors du pre-flight CORS (donc regarder ce qui s'échange dans l'onglet network du debugger). Un truc que j'ai vu régulièrement passer avec le CORS, c'est qu'il soit appliqué sur un controlleur nécessitant de l'authentification pour tout. Vu que le browser envoie la requête pre-flight sans rien de sensible, en général elle ne passe pas le filtre d'authentification et on reçois un 403 ou un 401 ce que le browser interprête comme "pas de CORS".

  5. #5
    Membre expert

    Homme Profil pro
    Informagicien ès Java
    Inscrit en
    janvier 2004
    Messages
    2 297
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Suisse

    Informations professionnelles :
    Activité : Informagicien ès Java
    Secteur : Finance

    Informations forums :
    Inscription : janvier 2004
    Messages : 2 297
    Points : 3 641
    Points
    3 641

    Par défaut

    Et aussi, je ne mettrais pas cela sous forme d'annotations dans le code. Il y a fort à parier que cette config ne soit valable qu'en mode dev et doive être désactivée lors des déploiement réels (typique de l'utilisation de nodejs - le backend est exposé sur un port différent du front).

    Donc, plutôt configurer un filter avec de l'xml qu'une annotation Java (filter qui sera supprimé de la config finale): https://spring.io/blog/2015/06/08/co...ring-framework

    M'enfin c'est personnel
    "Le plug gros problème des citations trouvées sur internet, c'est qu'on ne peut jamais garantir leur authenticité"

    Confucius, 448 av. J-C

Discussions similaires

  1. Réponses: 7
    Dernier message: 26/02/2019, 08h07
  2. [5.6] erreur Cross-Origin Request
    Par cobos dans le forum Laravel
    Réponses: 5
    Dernier message: 04/08/2018, 16h39
  3. erreur : No 'Access-Control-Allow-Origin'
    Par ThomasCastro dans le forum CakePHP
    Réponses: 2
    Dernier message: 18/09/2016, 01h20
  4. Appliquer un filtre? (erreur Access-Control-Allow-Origin)
    Par Ma29200 dans le forum GWT et Vaadin
    Réponses: 9
    Dernier message: 21/03/2013, 19h09
  5. Access Control Allow Origin dans .htaccess
    Par gégé140488 dans le forum Général JavaScript
    Réponses: 0
    Dernier message: 05/01/2012, 20h28

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo