---
# System prepended metadata

title: Angular LIFF
tags: [chatgpt]

---

# Angular LIFF

[TOC]

###### tags: `chatgpt`

---

## 一個 Angular 14 專案可以不用 routing 做到 multiple pages 嗎

Angular 14 專案可以不使用路由 (routing) 模組實現多頁面應用，但是這樣做可能會增加程式碼的複雜度，並且降低應用的可維護性。

如果您想要實現多頁面應用，建議使用 Angular 的路由模組。路由模組提供了一個簡單而強大的方式來將應用分成多個獨立的頁面，並且可以透過 URL 進行導航。此外，路由模組還提供了多種特性，如路由守衛、動態路由、延遲載入等，讓您可以更加靈活地控制應用的行為。

如果您仍然想要在不使用路由模組的情況下實現多頁面應用，您可以使用 `ngIf` 或 `ngSwitch` 等內建的 Angular 指令來顯示或隱藏不同的組件，從而達到類似多頁面的效果。但是，這樣做可能會導致程式碼難以維護和擴展，因此建議還是使用路由模組來實現多頁面應用。

## 在 Angular 14 如何透過 LIFF 取得的 access token 向後端呼叫 REST API

在 Angular 14 中，您可以透過 `HttpClient` 模組向後端呼叫 REST API。要使用 LIFF 取得的 access token，您可以將它傳遞到後端 API 的授權標頭中。

以下是示範程式碼：

1. 在 Angular 14 中使用 `HttpClient` 模組呼叫後端 API：

```typescript
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { Observable } from 'rxjs';

@Injectable()
export class ApiService {
	private apiUrl = 'https://your.api.endpoint'; // 替換為您的 API 端點

	constructor(private http: HttpClient) { }

	// GET 請求
	get<T>(path: string, headers?: HttpHeaders): Observable<T> {
		const options = {
			headers: headers || new HttpHeaders(),
		};
		return this.http.get<T>(`${this.apiUrl}/${path}`, options);
	}

	// POST 請求
	post<T>(path: string, body: any, headers?: HttpHeaders): Observable<T> {
		const options = {
			headers: headers || new HttpHeaders(),
		};
		return this.http.post<T>(`${this.apiUrl}/${path}`, body, options);
	}

	// PUT 請求
	put<T>(path: string, body: any, headers?: HttpHeaders): Observable<T> {
		const options = {
			headers: headers || new HttpHeaders(),
		};
		return this.http.put<T>(`${this.apiUrl}/${path}`, body, options);
	}

	// DELETE 請求
	delete<T>(path: string, headers?: HttpHeaders): Observable<T> {
		const options = {
			headers: headers || new HttpHeaders(),
		};
		return this.http.delete<T>(`${this.apiUrl}/${path}`, options);
	}
}
```

2. 在您的元件中使用 `ApiService`：

```typescript
import { Component, OnInit } from '@angular/core';
import { ApiService } from './api.service';

@Component({
	selector: 'app-root',
	templateUrl: './app.component.html',
	styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
	constructor(private apiService: ApiService) { }

	ngOnInit() {
		// 取得 LIFF access token
		const accessToken = '<YOUR_LIFF_ACCESS_TOKEN>';

		// 設定授權標頭
		const headers = {
			'Authorization': `Bearer ${accessToken}`,
		};

		// 呼叫 API
		this.apiService.get<any>('your-api-endpoint', headers).subscribe(
			response => {
				console.log(response);
			},
			error => {
				console.error(error);
			}
		);
	}
}
```

請注意替換示範程式碼中的 `<YOUR_LIFF_ACCESS_TOKEN>` 為您實際從 LIFF 取得的 access token，以及 `your-api-endpoint` 為您的後端 API 端點。

## 將 `<YOUR_LIFF_ACCESS_TOKEN>` 改寫為實際從 LIFF 取得的 access token

當您在實際應用程式中使用 LIFF 取得 access token 時，您需要將 `<YOUR_LIFF_ACCESS_TOKEN>` 取代為 LIFF 取得的實際 access token。

以下是一個示範程式碼，展示如何將 LIFF 取得的 access token 傳遞到後端 API 的授權標頭中：

```typescript
import { Component, OnInit } from '@angular/core';
import { ApiService } from './api.service';

@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
	constructor(private apiService: ApiService) { }

	ngOnInit() {
		// 從 LIFF 取得 access token
		const accessToken = liff.getAccessToken();

		// 設定授權標頭
		const headers = {
			'Authorization': `Bearer ${accessToken}`,
		};

		// 呼叫 API
		this.apiService.get<any>('your-api-endpoint', headers).subscribe(
			response => {
				console.log(response);
			},
			error => {
				console.error(error);
			}
		);
	}
}
```

請注意替換示範程式碼中的 `your-api-endpoint` 為您的後端 API 端點。

## 這個範例並未使用 LINE 官方的 `@line/liff`

非常抱歉，我的錯誤。如果您使用 `@line/liff` 模組，可以使用以下程式碼來向後端 API 傳遞 LIFF 取得的 access token：

```typescript
import { Component, OnInit } from '@angular/core';
import { ApiService } from './api.service';
import liff from '@line/liff';

@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
	constructor(private apiService: ApiService) { }

	async ngOnInit() {
		// 初始化 LIFF
		await liff.init({ liffId: 'YOUR_LIFF_ID' }); // 替換為您的 LIFF ID

		// 取得 LIFF access token
		const accessToken = await liff.getAccessToken();

		// 設定授權標頭
		const headers = {
			'Authorization': `Bearer ${accessToken}`,
		};

		// 呼叫 API
		this.apiService.get<any>('your-api-endpoint', headers).subscribe(
			response => {
				console.log(response);
			},
			error => {
				console.error(error);
			}
		);
	}
}
```

請注意替換示範程式碼中的 `YOUR_LIFF_ID` 為您實際的 LIFF ID，以及 `your-api-endpoint` 為您的後端 API 端點。

## 倘若後端 API 端點是 GET 但需要傳送 request body 呢

一般來說，HTTP GET 請求是沒有 request body 的。如果您需要向後端 API 傳送較大的資料，建議您改用 HTTP POST 請求，並將資料放在 request body 中。

不過，如果您一定要在 HTTP GET 請求中傳送 request body，您可以使用 URLSearchParams 類別將資料附加到 URL 查詢字串中。以下是一個範例程式碼：

```typescript
import { Component, OnInit } from '@angular/core';
import { ApiService } from './api.service';
import liff from '@line/liff';

@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
	constructor(private apiService: ApiService) { }

	async ngOnInit() {
		// 初始化 LIFF
		await liff.init({ liffId: 'YOUR_LIFF_ID' }); // 替換為您的 LIFF ID

		// 取得 LIFF access token
		const accessToken = await liff.getAccessToken();

		// 建立 URLSearchParams 物件並添加資料
		const params = new URLSearchParams();
		params.set('data1', 'value1');
		params.set('data2', 'value2');

		// 設定授權標頭
		const headers = {
			'Authorization': `Bearer ${accessToken}`,
		};

		// 呼叫 API
		this.apiService.get<any>(`your-api-endpoint?${params.toString()}`, headers).subscribe(
			response => {
				console.log(response);
			},
			error => {
				console.error(error);
			}
		);
	}
}
```

請注意，在這個範例中，我們使用了 `URLSearchParams` 來將資料添加到 URL 查詢字串中，然後將 URL 字串傳遞給 `apiService.get()` 方法中，作為 API 端點的 URL。最後，將授權標頭加入 HTTP 請求中。

## 但這個 GET 端點的 request body 必須是 JSON 怎麼辦

HTTP GET 請求的 request body 不應該是 JSON 格式的，因為它不符合 HTTP 規範。一般而言，HTTP GET 請求只能透過 URL 查詢字串傳遞參數，而不能使用 request body。

如果您的後端 API 端點要求 JSON 格式的 request body，建議您改用 HTTP POST 或 PUT 請求，將 JSON 資料放在 request body 中傳送。您可以使用 Angular 的 `HttpClient` 類別的 `post()` 或 `put()` 方法，並在請求的 headers 中指定 `Content-Type: application/json`，表示傳送的資料是 JSON 格式。

以下是一個範例程式碼，用於發送 HTTP POST 請求：

```typescript
import { Component, OnInit } from '@angular/core';
import { ApiService } from './api.service';
import liff from '@line/liff';

@Component({
	selector: 'app-root',
	templateUrl: './app.component.html',
	styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
	constructor(private apiService: ApiService) { }

	async ngOnInit() {
		// 初始化 LIFF
		await liff.init({ liffId: 'YOUR_LIFF_ID' }); // 替換為您的 LIFF ID

		// 取得 LIFF access token
		const accessToken = await liff.getAccessToken();

		// 建立要傳送的 JSON 資料
		const data = {
			key1: 'value1',
			key2: 'value2'
		};

		// 設定授權標頭與 Content-Type
		const headers = {
			'Authorization': `Bearer ${accessToken}`,
			'Content-Type': 'application/json'
		};

		// 呼叫 API
		this.apiService.post<any>('your-api-endpoint', data, headers).subscribe(
			response => {
				console.log(response);
			},
			error => {
				console.error(error);
			}
		);
	}
}
```

請注意，在這個範例中，我們使用了 `HttpClient` 類別的 `post()` 方法，並在 headers 中指定了 `Content-Type: application/json`，表示傳送的資料是 JSON 格式。

## 倘若不使用內建的 `HttpClient` 改用其它函式庫呢

Angular 內建的 `HttpClient` 已經提供了方便的方法可以處理 HTTP 請求，但如果您想要使用其他的 HTTP 函式庫，例如 **axios**、**fetch** 或 **request** 等，您也可以照樣透過指定 `Authorization` 標頭，將 LIFF access token 傳送到後端 API。

以下是一個使用 **axios** 函式庫傳送 HTTP POST 請求的範例程式碼：

```typescript
import { Component, OnInit } from '@angular/core';
import axios from 'axios';
import liff from '@line/liff';

@Component({
	selector: 'app-root',
	templateUrl: './app.component.html',
	styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {

	constructor() { }

	async ngOnInit() {
		// 初始化 LIFF
		await liff.init({ liffId: 'YOUR_LIFF_ID' }); // 替換為您的 LIFF ID

		// 取得 LIFF access token
		const accessToken = await liff.getAccessToken();

		// 建立要傳送的 JSON 資料
		const data = {
			key1: 'value1',
			key2: 'value2'
		};

		// 設定授權標頭與 Content-Type
		const headers = {
			'Authorization': `Bearer ${accessToken}`,
			'Content-Type': 'application/json'
		};

		// 設定 axios 的配置項
		const config = {
			headers: headers
		};

		// 呼叫 API
		axios
			.post('your-api-endpoint', data, config)
			.then(response => {
				console.log(response);
			})
			.catch(error => {
				console.error(error);
			});
	}
}
```

在這個範例中，我們使用 axios 函式庫的 `post()` 方法，並在 `config` 中指定 headers，其中包含 LIFF access token 和 `Content-Type` 標頭。注意，這個範例中的程式碼並未將 accessToken 進行錯誤處理，請務必自行加上適當的錯誤處理程式碼。

## axios 能否在 GET 端點使用 JSON 的 request body

在一般的 REST API 設計中，GET 請求並不應該使用 request body，而是應該透過 query string 傳遞參數。因此，大多數的 HTTP 函式庫，包括 axios，預設並不支援在 GET 請求中傳送 request body。

不過，如果您一定需要在 GET 請求中傳送 request body，有一些 HTTP 函式庫提供了相關的功能。例如，您可以使用 axios 的 params 選項傳送 JSON 格式的資料，並將 `Content-Type` 標頭設定為 `application/json`，如下所示：

```typescript
const data = {
	key1: 'value1',
	key2: 'value2'
};

const headers = {
	'Content-Type': 'application/json'
};

const config = {
	params: data,
	headers: headers
};

axios
	.get('your-api-endpoint', config)
	.then(response => {
		console.log(response);
	})
	.catch(error => {
		console.error(error);
	});
```

在這個範例中，我們將要傳送的 JSON 資料設定為 `data`，並將 `Content-Type` 標頭設定為 `application/json`。接著，我們在 `config` 中使用 `params` 選項傳送 `data`，並將 `headers` 設定為我們剛剛設定的 `headers`。最後，我們使用 `axios.get()` 方法傳送 GET 請求，並將 `config` 作為第二個參數傳入。這樣就可以在 GET 請求中傳送 JSON 格式的 request body 了。
