Angular×SpringBoot　HttpClientでハマったのでメモ

SPAを作ろうとAngularに安易に手を出し、ハマったのでメモ

## 1.subscribeは必ず書く

まず接続テストだけのつもりでsubscribeメソッドを書かずにいたら全然つながらなかった

下記のgetItemとgetItem2のメソッドの違いはHttpResponse型で受け取るかどうかだけです


```typescript:sample.service.ts

export interface Item{
  title:string;
}

export class MaterialService {
  //Angularでリバースプロキシ設定する場合
  //private host: string = '/api';

  //Angularでリバースプロキシ設定しない場合
  private host: string = 'http://localhost:8080/api/v1';

  constructor(private http: HttpClient) {}

  getItem(){
    const rtn:Observable<HttpResponse<Item>> = this.http.get<Item>(this.host+'/sample',{observe:'response'}).pipe(
      timeout(5000),
      catchError(this.handleError)
    );
    //この時点ではまだHTTP通信はされてない
    //下記のsubscribeメソッドを実装してはじめて通信はしるよう
    rtn.subscribe({
      next:(response:HttpResponse<Item>) => {
        console.log('subscribe next')
        console.log(response)   
        //「title」が存在しなくてもエラーにはならず[undifined]
        console.log(response.body?.title)
      },
      error:(e)=>{
        //404の時など、handleErrorの後に実行される
        console.log('subscribe error')
        console.log(e);
      }
    });
  }

  getItem2(){
    const rtn:Observable<Item> = this.http.get<Item>(this.host+'/sample').pipe(
      timeout(5000),
      catchError(this.handleError)
    );

    rtn.subscribe({
      next:(response:Item) => {
        console.log('subscribe next')
        console.log(response)
        //「title」が存在しなくてもエラーにはならず[undifined]
        console.log(response.title)
      },
      error:(e)=>{
        //404の時など、handleErrorの後に実行される
        console.log('subscribe error')
        console.log(e);
      }
    });
  }


  private handleError(error: HttpErrorResponse) {
    console.log('handleError');
    if (error.status === 0) {
      // A client-side or network error occurred. Handle it accordingly.
      console.error('An error occurred:', error.error);
    } else {
      // The backend returned an unsuccessful response code.
      // The response body may contain clues as to what went wrong.
      console.error(
        `Backend returned code ${error.status}, body was: `, error.error);
    }
    // Return an observable with a user-facing error message.
    return throwError(() => new Error('Something bad happened; please try again later.'));
  }
}
```

## 2.CORSエラー対策
CORSエラーが発生するので以下３つのいずれかが必要
CORSについて参考サイト：
https://b1san-blog.com/post/spring/spring-cors/

### ①Angularでリバースプロキシ設定
下記をAngularのプロジェクトルートへ配置後、
「ng serve --proxy-config proxy.conf.json」で起動させる

```json:proxy.conf.json
{
    "/api": {
        "target": "http://localhost:8080/api/v1",
        "pathRewrite": {
            "^/api": ""
        }
    }
}
```

### ②SpringBootでWebConfig作成
```java:WebConfig
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
class WebConfig implements WebMvcConfigurer {
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
        .allowedOrigins("*")
        .allowedMethods("*");
    }
}
```

### ③SpringBootのControllerに@CrossOriginを付ける
```java:AngularRestController
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@CrossOrigin//これ
@RequestMapping("/api/v1")
public class AngularRestController {;

  @GetMapping("/sample")
  public String getAll() {
      return "{\"title\":\"app\"}";
  }
}

```