Now.js Framework Documentation

Now.js Framework Documentation

HttpClient - ไคลเอนต์ HTTP ระดับต่ำ

TH 31 Oct 2025 01:09

HttpClient - ไคลเอนต์ HTTP ระดับต่ำ

เอกสารสำหรับ HttpClient ซึ่งเป็นไคลเอนต์ HTTP ระดับต่ำของ Now.js Framework

📋 สารบัญ

  1. ภาพรวม
  2. การติดตั้งและนำเข้า
  3. Exports ทั้งหมด
  4. คลาส HttpClient
  5. อินสแตนซ์ http
  6. อินสแตนซ์ httpthrow
  7. ยูทิลิตี้ simpleFetch
  8. ตัวดัก Interceptor
  9. การป้องกัน csrf
  10. ฟีเจอร์ด้านความปลอดภัย
  11. การจัดการข้อผิดพลาด
  12. ตัวอย่างการใช้งาน
  13. เอกสารอ้างอิง api
  14. แนวปฏิบัติที่ดีที่สุด

ภาพรวม

HttpClient เป็น Low-level HTTP Client ที่สร้างจาก Fetch API มีฟีเจอร์ที่ทันสมัยและปลอดภัย เหมาะสำหรับการเรียก API ที่ต้องการการควบคุมระดับต่ำ

ฟีเจอร์หลัก

  • 4 Exports: HttpClient, http, httpThrow, simpleFetch
  • Interceptors: Request และ Response interceptors
  • CSRF Protection: ป้องกัน CSRF attacks
  • Auto Content-Type Detection: ตรวจจับและแปลง response อัตโนมัติ
  • Timeout Support: กำหนด timeout สำหรับ requests
  • Error Handling: จัดการ errors แบบยืดหยุ่น
  • Custom Response Handler: กำหนดวิธีจัดการ response เอง
  • AbortController Support: ยกเลิก requests ได้
  • FormData/Blob/ArrayBuffer Support: รองรับ content types หลากหลาย

การติดตั้งและนำเข้า

HttpClient โหลดมาพร้อมกับ Now.js Framework และพร้อมใช้งานทันทีผ่าน window object:

// ไม่ต้อง import - พร้อมใช้งานทันที
console.log(window.http);        // อินสแตนซ์ http
console.log(window.httpThrow);   // อินสแตนซ์ httpThrow
console.log(window.simpleFetch); // ยูทิลิตี้ simpleFetch
console.log(window.HttpClient);  // คลาส HttpClient

Exports ทั้งหมด

HttpClient มี 4 exports หลัก ที่ให้ใช้งาน:

Export ประเภท throwOnError กรณีใช้งาน
HttpClient คลาส ตามที่กำหนด สร้างอินสแตนซ์แบบกำหนดเอง
http อินสแตนซ์ false การใช้งานทั่วไป (โหมดปลอดภัย)
httpThrow อินสแตนซ์ true การใช้งานที่ต้องการให้ throw error
simpleFetch อ็อบเจ็กต์ยูทิลิตี้ N/A การใช้งานแบบเบาและรวดเร็ว

คลาส HttpClient

คอนสตรักเตอร์

สร้าง HttpClient instance ใหม่:

const client = new HttpClient(options);

ตัวเลือก

ตัวเลือก ประเภท ค่าเริ่มต้น คำอธิบาย
baseURL string '' Base URL สำหรับทุก request
headers object {} Header เริ่มต้น
timeout number 30000 เวลา timeout หน่วยมิลลิวินาที
throwOnError boolean true ให้ throw error เมื่อ response ไม่สำเร็จ
responseHandler function null ฟังก์ชันจัดการ response แบบกำหนดเอง
csrfCookieName string 'XSRF-TOKEN' ชื่อคุกกี้สำหรับ CSRF
csrfTokenSelector string 'meta[name="csrf-token"]' ตัวเลือก CSS สำหรับ meta tag CSRF
security object {} การตั้งค่าด้านความปลอดภัย

ตัวอย่างการสร้าง Instance

// อินสแตนซ์พื้นฐาน
const api = new HttpClient({
  baseURL: 'https://api.example.com',
  timeout: 10000
});

// อินสแตนซ์ที่เปิดใช้การป้องกัน CSRF
const secureApi = new HttpClient({
  baseURL: 'https://api.example.com',
  security: {
    csrf: {
      enabled: true,
      tokenName: '_token',
      headerName: 'X-CSRF-Token'
    }
  }
});

// อินสแตนซ์ที่กำหนด response handler เอง
const customApi = new HttpClient({
  baseURL: 'https://api.example.com',
  responseHandler: async (response) => {
    const data = await response.json();
    return {
      success: response.ok,
      result: data,
      timestamp: Date.now()
    };
  }
});

เมธอด

เมธอด HTTP

// ส่งคำขอแบบ GET
await client.get(url, options);

// ส่งคำขอแบบ POST
await client.post(url, data, options);

// ส่งคำขอแบบ PUT
await client.put(url, data, options);

// ส่งคำขอแบบ DELETE
await client.delete(url, options);

// ส่งคำขอแบบ PATCH
await client.patch(url, data, options);

// ส่งคำขอแบบ HEAD
await client.head(url, options);

// ส่งคำขอแบบ OPTIONS
await client.options(url, options);

เมธอดโหมดปลอดภัย (ไม่ throw error)

// ส่ง GET แบบโหมดปลอดภัย
await client.getSafe(url, options);

// ส่ง POST แบบโหมดปลอดภัย
await client.postSafe(url, data, options);

// ส่ง PUT แบบโหมดปลอดภัย
await client.putSafe(url, data, options);

// ส่ง DELETE แบบโหมดปลอดภัย
await client.deleteSafe(url, options);

เมธอดอัปโหลด

// อัปโหลดไฟล์เดียว
await client.upload('/api/upload', file);

// อัปโหลดหลายไฟล์
await client.upload('/api/upload', [file1, file2]);

// อัปโหลดพร้อมข้อมูลเพิ่มเติม
await client.upload('/api/upload', files, {
  data: {
    title: 'My Upload',
    category: 'images'
  }
});

เมธอดปรับแต่งค่า

// ตั้งค่า Base URL
client.setBaseURL('https://api.example.com');

// ตั้งค่า Header เดียวเป็นค่าเริ่มต้น
client.setDefaultHeader('Authorization', 'Bearer token');

// ตั้งค่า Header เริ่มต้นหลายรายการ
client.setDefaultHeaders({
  'X-App-Version': '1.0.0',
  'X-Device-ID': 'abc123'
});

// ตั้งค่า Timeout (60 วินาที)
client.setTimeout(60000); // 60 วินาที

// ตั้งค่า CSRF Token
client.setCsrfToken('token-value');

อินสแตนซ์ http

Instance พร้อมใช้งานที่มี throwOnError: false เหมาะสำหรับการใช้งานทั่วไป

คุณสมบัติ

  • ❌ ไม่ throw errors (ต้องตรวจสอบ response.ok เอง)
  • ✅ มี timestamp และ requestId ใน response
  • ✅ Auto-parse response ตาม Content-Type

การใช้งาน

// ตัวอย่างคำขอ GET
const response = await http.get('/api/users');

if (response.ok) {
  console.log(response.data);
  console.log('Timestamp:', response.timestamp);
  console.log('Request ID:', response.requestId);
} else {
  console.error('Error:', response.statusText);
}

// ตัวอย่างคำขอ POST
const response = await http.post('/api/users', {
  name: 'John Doe',
  email: 'john@example.com'
});

if (response.ok) {
  console.log('Created:', response.data);
}

อ็อบเจ็กต์ Response

{
  ok: boolean,              // true หากสถานะ 200-299
  status: number,           // รหัสสถานะ HTTP
  statusText: string,       // ข้อความสถานะ HTTP
  data: any,                // ข้อมูล response ที่แปลงแล้ว
  headers: object,          // Header ของ response
  url: string,              // URL ที่เรียก
  timestamp: number,        // เวลาที่ตอบกลับ (เฉพาะ http instance)
  requestId: string|null    // รหัสคำขอจาก header (เฉพาะ http instance)
}

อินสแตนซ์ httpThrow

Instance พร้อมใช้งานที่มี throwOnError: true เหมาะสำหรับการใช้งานที่ต้องการ try-catch

คุณสมบัติ

  • ✅ Throw HttpError เมื่อ response ไม่สำเร็จ
  • ✅ มี timestamp และ requestId ใน response
  • ✅ Return format แตกต่างจาก http เล็กน้อย

การใช้งาน

try {
  // ตัวอย่างคำขอ GET
  const response = await httpThrow.get('/api/users');
  console.log(response.data);
  console.log('ข้อความ:', response.message);

} catch (error) {
  console.error('Error:', error.message);
  console.error('Status:', error.status);
  console.error('Response:', error.response);
}

// ตัวอย่างคำขอ POST
try {
  const response = await httpThrow.post('/api/users', {
    name: 'John Doe',
    email: 'john@example.com'
  });
  console.log('สร้างสำเร็จ:', response.data);

} catch (error) {
  if (error.status === 422) {
    console.error('ข้อมูลไม่ผ่านการตรวจสอบ:', error.response.data);
  } else {
    console.error('ข้อผิดพลาดจากเซิร์ฟเวอร์:', error.message);
  }
}

อ็อบเจ็กต์ Response (สำเร็จ)

{
  status: number,           // รหัสสถานะ HTTP
  data: any,                // ข้อมูล response ที่แปลงแล้ว
  message: string,          // ข้อความจากเซิร์ฟเวอร์หรือ statusText
  meta: any,                // ข้อมูลเสริมจากเซิร์ฟเวอร์ (ถ้ามี)
  timestamp: number,        // เวลาที่ตอบกลับ
  headers: object,          // Header ของ response
  requestId: string|null    // รหัสคำขอจาก header
}

อ็อบเจ็กต์ HttpError (Error)

{
  name: 'HttpError',
  message: string,          // ข้อความข้อผิดพลาด
  status: number,           // รหัสสถานะ HTTP
  response: object,         // อ็อบเจ็กต์ response แบบเต็ม
  timestamp: number         // เวลาที่เกิดข้อผิดพลาด
}

ยูทิลิตี้ simpleFetch

Lightweight fetch wrapper ที่ออกแบบมาให้ใช้งานง่ายและเบา เหมาะสำหรับการเรียก API แบบง่ายๆ

คุณสมบัติ

  • ✅ Zero dependencies (ใช้ fetch API เพียงอย่างเดียว)
  • ✅ Auto-parsing response (JSON, Text, Blob)
  • ✅ Convenience methods (.json(), .text(), .postJson())
  • ✅ Auto-attach bearer token จาก localStorage
  • ✅ Timeout support (default 15 seconds)
  • ✅ Method chaining สำหรับ configuration

เมธอด HTTP

เมธอดมาตรฐาน (คืนค่าอ็อบเจ็กต์ response)

// ขอข้อมูลแบบ GET
const response = await simpleFetch.get('/api/users');
if (response.ok) {
  console.log(response.data);
}

// ขอข้อมูลแบบ POST
const response = await simpleFetch.post('/api/users', {
  name: 'John Doe'
});

// ขอข้อมูลแบบ PUT
const response = await simpleFetch.put('/api/users/1', {
  name: 'Jane Doe'
});

// ขอข้อมูลแบบ DELETE
const response = await simpleFetch.delete('/api/users/1');

// ขอข้อมูลแบบ PATCH
const response = await simpleFetch.patch('/api/users/1', {
  status: 'active'
});

เมธอดแบบสะดวก (คืนค่า data โดยตรง)

// ดึงข้อมูล JSON โดยตรง
const users = await simpleFetch.json('/api/users');
console.log(users); // รายชื่อผู้ใช้หรือ null

// ดึงข้อมูลแบบข้อความโดยตรง
const html = await simpleFetch.text('/api/template');
console.log(html); // สตริง HTML หรือ null

// ส่ง JSON แล้วรับคำตอบโดยตรง
const newUser = await simpleFetch.postJson('/api/users', {
  name: 'John Doe'
});
console.log(newUser); // อ็อบเจ็กต์ผู้ใช้ที่สร้างใหม่หรือ null

การอัปโหลดไฟล์

// อัปโหลดไฟล์เดียว
const response = await simpleFetch.upload('/api/upload', file);

// อัปโหลดหลายไฟล์
const response = await simpleFetch.upload('/api/upload', [file1, file2]);

// อัปโหลดพร้อมข้อมูลเพิ่มเติม
const response = await simpleFetch.upload('/api/upload', files, {
  title: 'My Photos',
  category: 'vacation'
});

// อัปโหลดด้วย FormData
const formData = new FormData();
formData.append('file', file);
formData.append('title', 'Photo');
const response = await simpleFetch.upload('/api/upload', formData);

การปรับแต่งค่า

// ตั้งค่า Base URL
simpleFetch.setBaseURL('https://api.example.com');

// ตั้งค่า Header เริ่มต้นหลายรายการ
simpleFetch.setHeaders({
  'X-App-Version': '1.0.0',
  'X-Device-ID': 'abc123'
});

// ตั้งค่า Header รายตัว
simpleFetch.setHeader('X-Custom-Header', 'value');

// ตั้งค่า Timeout (30 วินาที)
simpleFetch.setTimeout(30000); // 30 วินาที

// ลบ Header
simpleFetch.removeHeader('X-Custom-Header');

// รีเซ็ตการตั้งค่าทั้งหมด
simpleFetch.resetConfig();

// ตัวอย่างการใช้งานแบบ Method Chaining
simpleFetch
  .setBaseURL('https://api.example.com')
  .setTimeout(10000)
  .setHeader('X-App-Version', '1.0.0');

การแนบ Bearer Token อัตโนมัติ

simpleFetch จะดึง bearer token จาก localStorage.getItem('auth_token') อัตโนมัติและใส่ใน Authorization header:

// ถ้ามี token ใน localStorage
localStorage.setItem('auth_token', 'your-token');

// simpleFetch จะใส่ header นี้อัตโนมัติ:
// Authorization: Bearer your-token

const response = await simpleFetch.get('/api/user/profile');

อ็อบเจ็กต์ Response

{
  ok: boolean,              // true หากสถานะ 200-299
  status: number,           // รหัสสถานะ HTTP
  statusText: string,       // ข้อความสถานะ HTTP
  data: any,                // ข้อมูลที่แปลงแล้ว (หรือ null)
  headers: object,          // Header ของ response
  url: string,              // URL ที่เรียก
  error: Error              // อ็อบเจ็กต์ข้อผิดพลาด (ถ้ามี)
}

ตัวดัก Interceptor

Interceptors ช่วยให้คุณสามารถแก้ไข request หรือ response ก่อนที่จะส่งหรือรับ

ตัวดักฝั่ง Request

แก้ไข request config ก่อนส่ง request:

// เพิ่ม request interceptor
const removeInterceptor = http.addRequestInterceptor(config => {
  // แก้ไข config
  config.headers['X-Timestamp'] = Date.now();
  config.headers['X-User-Agent'] = navigator.userAgent;

  // ต้อง return config
  return config;
});

// ลบ interceptor
removeInterceptor();

ตัวดักฝั่ง Response

จัดการ response หลังได้รับจาก server:

// เพิ่ม response interceptor
const removeInterceptor = http.addResponseInterceptor(
  // onFulfilled - จัดการ response ที่สำเร็จ
  (response) => {
    console.log('Response received:', response.status);

    // แก้ไข response ถ้าต้องการ
    response.receivedAt = Date.now();

    return response;
  },

  // onRejected - จัดการ response ที่มีข้อผิดพลาด
  (error) => {
    console.error('Response error:', error);

    // แก้ไข error หรือ throw ต่อ
    if (error.status === 401) {
      // เปลี่ยนเส้นทางไปหน้าเข้าสู่ระบบ
      window.location.href = '/login';
    }

    throw error;
  }
);

// ลบ interceptor
removeInterceptor();

ตัวอย่างการใช้งาน Interceptor

1. เพิ่ม Authentication Token

http.addRequestInterceptor(config => {
  const token = localStorage.getItem('auth_token');
  if (token) {
    config.headers['Authorization'] = `Bearer ${token}`;
  }
  return config;
});

2. การบันทึก Log

// บันทึกคำขอ
http.addRequestInterceptor(config => {
  console.log(`[${config.method}] ${config.url}`);
  return config;
});

// บันทึกการตอบกลับ
http.addResponseInterceptor(
  response => {
    console.log(`[${response.status}] ${response.url}`);
    return response;
  },
  error => {
    console.error(`[Error] ${error.status} - ${error.message}`);
    throw error;
  }
);

3. ลองใหม่เมื่อเกิดข้อผิดพลาดเครือข่าย

http.addResponseInterceptor(
  response => response,
  async (error) => {
    if (error.status === 0 || error.status === 408) {
      console.log('Network error, retrying...');

  // ลองเรียกคำขอเดิมอีกครั้ง
      return await http.request(error.url);
    }
    throw error;
  }
);

4. แปลงโครงสร้าง Response

http.addResponseInterceptor(response => {
  // แปลง response format
  return {
    success: response.ok,
    result: response.data,
    errors: response.ok ? null : response.data?.errors,
    timestamp: Date.now()
  };
});

5. จำกัดอัตราการเรียก (Rate Limiting)

const requestTimestamps = [];

http.addRequestInterceptor(config => {
  const now = Date.now();

  // ลบ timestamps ที่เก่ากว่า 1 นาที
  const oneMinuteAgo = now - 60000;
  while (requestTimestamps.length && requestTimestamps[0] < oneMinuteAgo) {
    requestTimestamps.shift();
  }

  // ตรวจสอบ rate limit (max 60 requests/minute)
  if (requestTimestamps.length >= 60) {
    throw new Error('Rate limit exceeded. Please wait.');
  }

  requestTimestamps.push(now);
  return config;
});

การป้องกัน CSRF

HttpClient มี CSRF protection built-in เพื่อป้องกัน Cross-Site Request Forgery attacks

การเปิดใช้งาน CSRF

const client = new HttpClient({
  security: {
    csrf: {
      enabled: true,
      tokenName: '_token',
      headerName: 'X-CSRF-Token'
    }
  }
});

วิธีการทำงาน

CSRF token จะถูกดึงจาก:

  1. Meta tag (<meta name="csrf-token" content="token-value">)
  2. Cookie (ชื่อ XSRF-TOKEN โดย default)
<!-- ในส่วน <head> -->
<meta name="csrf-token" content="your-csrf-token-here">

การแนบ CSRF Token อัตโนมัติ

Token จะถูกแนบอัตโนมัติใน:

  • Header: X-CSRF-Token: token-value
  • Request Body: สำหรับ POST/PUT/DELETE requests
// Token จะถูกแนบอัตโนมัติ
await client.post('/api/delete-item', { id: 123 });

// Request จะมี:
// Header: X-CSRF-Token: your-token
// Body: { id: 123, _token: 'your-token' }

การตั้งค่า CSRF Token ด้วยตนเอง

// ตั้งค่า token ด้วยตนเอง
client.setCsrfToken('new-token-value');

// Token จะถูกใช้ใน requests ต่อไป
await client.post('/api/action', data);

การต่ออายุ CSRF Token

HttpClient จะอัปเดต token อัตโนมัติจาก response header:

// เซิร์ฟเวอร์ส่ง header: X-CSRF-Token: new-token
const response = await client.post('/api/action', data);

// client.csrfToken จะถูกอัปเดตเป็น 'new-token' อัตโนมัติ

ฟีเจอร์ด้านความปลอดภัย

HttpClient มีฟีเจอร์ด้านความปลอดภัยหลายอย่างที่สามารถเปิดใช้งานได้

1. การป้องกัน CSRF

ป้องกัน Cross-Site Request Forgery:

const client = new HttpClient({
  security: {
    csrf: {
      enabled: true,
      tokenName: '_token',
      headerName: 'X-CSRF-Token'
    }
  }
});

2. การจำกัดอัตราการเรียก (Rate Limiting)

จำกัดจำนวน requests (ต้องใช้งานร่วมกับ SecurityManager):

const client = new HttpClient({
  security: {
    rateLimit: {
      enabled: true
    }
  }
});

3. การตรวจสอบความถูกต้องของ Request

ทำความสะอาดข้อมูลใน request (ต้องใช้งานร่วมกับ SecurityManager):

const client = new HttpClient({
  security: {
    validation: {
      enabled: true
    }
  }
});

4. การตั้งค่า Timeout

ป้องกัน requests ที่ค้างนาน:

const client = new HttpClient({
  timeout: 10000 // 10 วินาที
});

// หรือตั้งค่าทีหลัง
client.setTimeout(5000); // 5 วินาที

5. การส่ง Credentials เฉพาะโดเมนเดียวกัน

ป้องกันการส่ง credentials ข้าม domain:

const client = new HttpClient();

// ค่าเริ่มต้น: credentials: 'same-origin'
await client.get('/api/data');

// ต้องการส่ง credentials ข้ามโดเมน
await client.get('https://api.example.com/data', {
  credentials: 'include'
});

การจัดการข้อผิดพลาด

HttpClient มีหลายวิธีในการจัดการ errors

1. โหมดปลอดภัย (อินสแตนซ์ http)

ใช้ http instance ที่ไม่ throw errors:

const response = await http.get('/api/users');

if (response.ok) {
  console.log('Success:', response.data);
} else {
  console.error('Error:', response.status, response.statusText);

  // แสดง error message จาก server
  if (response.data?.message) {
    console.error('Server message:', response.data.message);
  }
}

2. โหมด Throw (อินสแตนซ์ httpThrow)

ใช้ httpThrow instance ที่ throw errors:

try {
  const response = await httpThrow.get('/api/users');
  console.log('Success:', response.data);

} catch (error) {
  console.error('Error:', error.message);
  console.error('Status:', error.status);

  // จัดการ error ตาม status code
  switch (error.status) {
    case 401:
      // เปลี่ยนเส้นทางไปหน้าเข้าสู่ระบบ
      window.location.href = '/login';
      break;

    case 403:
      alert('Access denied');
      break;

    case 404:
      alert('Resource not found');
      break;

    case 422:
      // ข้อมูลไม่ผ่านการตรวจสอบ
      const errors = error.response.data.errors;
      console.error('Validation errors:', errors);
      break;

    case 500:
      alert('Server error. Please try again later.');
      break;

    default:
      alert('An error occurred: ' + error.message);
  }
}

3. อินสแตนซ์แบบกำหนดเอง

สร้าง instance ที่มี error handling แบบกำหนดเอง:

const client = new HttpClient({
  throwOnError: false // หรือ true ตามต้องการ
});

// กำหนดค่า throwOnError เฉพาะคำขอ
const response = await client.get('/api/users', {
  throwOnError: true // ให้ throw error เฉพาะคำขอนี้
});

4. Interceptor สำหรับจัดการข้อผิดพลาด

ใช้ response interceptor เพื่อจัดการ errors:

http.addResponseInterceptor(
  response => response,
  error => {
    // บันทึกข้อผิดพลาด
    console.error('API Error:', error);

    // แสดงการแจ้งเตือน
    if (window.NotificationManager) {
      NotificationManager.error(error.message);
    }

    // เปลี่ยนเส้นทางเมื่อสิทธิ์หมดอายุ
    if (error.status === 401) {
      window.location.href = '/login';
      return; // ไม่ต้องโยนข้อผิดพลาดต่อ
    }

    // โยนข้อผิดพลาดอื่นต่อ
    throw error;
  }
);

5. ข้อผิดพลาดจาก Timeout

จัดการ timeout errors:

const response = await http.get('/api/slow-endpoint');

if (!response.ok && response.status === 408) {
  console.error('Request timeout');
  alert('The server is taking too long to respond. Please try again.');
}

อ็อบเจ็กต์ HttpError

try {
  await httpThrow.get('/api/users');
} catch (error) {
  console.log(error.name);      // 'HttpError'
  console.log(error.message);   // ข้อความข้อผิดพลาด
  console.log(error.status);    // รหัสสถานะ HTTP
  console.log(error.response);  // อ็อบเจ็กต์ response แบบเต็ม
  console.log(error.timestamp); // เวลาที่เกิดข้อผิดพลาด
}

ตัวอย่างการใช้งาน

1. การเรียก API แบบง่าย

// ใช้ simpleFetch
const users = await simpleFetch.json('/api/users');
console.log(users);

// ใช้ http
const response = await http.get('/api/users');
if (response.ok) {
  console.log(response.data);
}

2. การส่งข้อมูล JSON

// ตัวอย่างคำขอ POST
const response = await http.post('/api/users', {
  name: 'John Doe',
  email: 'john@example.com',
  age: 30
});

if (response.ok) {
  console.log('Created:', response.data);
}

// ตัวอย่างคำขอ PUT
const response = await http.put('/api/users/1', {
  name: 'Jane Doe',
  email: 'jane@example.com'
});

// ตัวอย่างคำขอ PATCH
const response = await http.patch('/api/users/1', {
  status: 'active'
});

3. การอัปโหลดไฟล์

// อัปโหลดไฟล์เดียว
const fileInput = document.querySelector('#file');
const file = fileInput.files[0];

const response = await http.upload('/api/upload', file);

if (response.ok) {
  console.log('Uploaded:', response.data.url);
}

// อัปโหลดหลายไฟล์พร้อมกัน
const files = Array.from(fileInput.files);
const response = await http.upload('/api/upload', files);

// อัปโหลดพร้อมส่งข้อมูลเพิ่มเติม
const response = await http.upload('/api/upload', file, {
  data: {
    title: 'Profile Picture',
    category: 'avatars'
  }
});

4. การใช้งาน FormData

const formData = new FormData();
formData.append('name', 'John Doe');
formData.append('email', 'john@example.com');
formData.append('avatar', file);

const response = await http.post('/api/users', formData);

5. การดาวน์โหลดไฟล์

const response = await http.get('/api/reports/download', {
  headers: {
    'Accept': 'application/pdf'
  }
});

if (response.ok) {
  // response.data จะเป็น Blob
  const blob = response.data;

  // สร้างลิงก์สำหรับดาวน์โหลด
  const url = URL.createObjectURL(blob);
  const a = document.createElement('a');
  a.href = url;
  a.download = 'report.pdf';
  a.click();
  URL.revokeObjectURL(url);
}

6. การใช้งาน Query Parameters

// สร้างพารามิเตอร์เอง
const response = await http.get('/api/users?page=1&limit=10&sort=name');

// ใช้ URLSearchParams
const params = new URLSearchParams({
  page: 1,
  limit: 10,
  sort: 'name'
});

const response = await http.get(`/api/users?${params}`);

7. การยกเลิก Request

const controller = new AbortController();

// เริ่มส่งคำขอ
const responsePromise = http.get('/api/large-data', {
  signal: controller.signal
});

// ยกเลิกหลังผ่านไป 5 วินาที
setTimeout(() => {
  controller.abort();
}, 5000);

try {
  const response = await responsePromise;
  console.log(response.data);
} catch (error) {
  if (error.name === 'AbortError') {
    console.log('ยกเลิกคำขอแล้ว');
  }
}

8. การใช้งาน Custom Headers

const response = await http.get('/api/data', {
  headers: {
    'X-Custom-Header': 'value',
    'Accept-Language': 'th',
    'X-App-Version': '1.0.0'
  }
});

9. การใช้งาน Authentication

// ตั้งค่า Bearer token
http.setDefaultHeader('Authorization', 'Bearer your-token-here');

// หรือใช้ interceptor เพื่อแนบ token อัตโนมัติ
http.addRequestInterceptor(config => {
  const token = localStorage.getItem('auth_token');
  if (token) {
    config.headers['Authorization'] = `Bearer ${token}`;
  }
  return config;
});

// กำหนด Basic Auth
const username = 'user';
const password = 'pass';
const credentials = btoa(`${username}:${password}`);

http.setDefaultHeader('Authorization', `Basic ${credentials}`);

10. การใช้งาน Base URL

// ตั้งค่า base URL
http.setBaseURL('https://api.example.com');

// ใช้งาน
await http.get('/users');        // เรียก https://api.example.com/users
await http.get('/posts');        // เรียก https://api.example.com/posts

// เรียก URL ภายนอกโดยไม่ใช้ base URL
await http.get('https://other-api.com/data'); // เรียก https://other-api.com/data

11. Parallel Requests

// รอ requests ทั้งหมดเสร็จ
const [users, posts, comments] = await Promise.all([
  http.get('/api/users'),
  http.get('/api/posts'),
  http.get('/api/comments')
]);

console.log('Users:', users.data);
console.log('Posts:', posts.data);
console.log('Comments:', comments.data);

// รอ request แรกที่เสร็จ
const response = await Promise.race([
  http.get('/api/fast-endpoint'),
  http.get('/api/slow-endpoint')
]);

12. Retry Logic

async function fetchWithRetry(url, maxRetries = 3) {
  for (let i = 0; i < maxRetries; i++) {
    const response = await http.get(url);

    if (response.ok) {
      return response;
    }

    // ลองใหม่เมื่อเกิดข้อผิดพลาดฝั่งเซิร์ฟเวอร์
    if (response.status >= 500 && i < maxRetries - 1) {
      console.log(`Retry ${i + 1}/${maxRetries}...`);
      await new Promise(resolve => setTimeout(resolve, 1000 * (i + 1)));
      continue;
    }

    return response;
  }
}

const response = await fetchWithRetry('/api/unstable-endpoint');

13. การติดตามความคืบหน้า (ขณะอัปโหลด)

// ใช้ XMLHttpRequest สำหรับ progress tracking
function uploadWithProgress(url, file, onProgress) {
  return new Promise((resolve, reject) => {
    const xhr = new XMLHttpRequest();
    const formData = new FormData();
    formData.append('file', file);

    xhr.upload.addEventListener('progress', (e) => {
      if (e.lengthComputable) {
        const percent = (e.loaded / e.total) * 100;
        onProgress(percent);
      }
    });

    xhr.addEventListener('load', () => {
      if (xhr.status >= 200 && xhr.status < 300) {
        resolve(JSON.parse(xhr.responseText));
      } else {
        reject(new Error(xhr.statusText));
      }
    });

    xhr.addEventListener('error', () => reject(new Error('Upload failed')));

    xhr.open('POST', url);
    xhr.send(formData);
  });
}

// ใช้งาน
const file = document.querySelector('#file').files[0];
const result = await uploadWithProgress('/api/upload', file, (percent) => {
  console.log(`กำลังอัปโหลด: ${percent.toFixed(2)}%`);
});

เอกสารอ้างอิง API

คลาส HttpClient

คอนสตรักเตอร์

new HttpClient(options?: HttpClientOptions): HttpClient

คุณสมบัติ

คุณสมบัติ ประเภท คำอธิบาย
baseURL string Base URL สำหรับทุก request
defaultHeaders object Header เริ่มต้น
timeout number เวลา timeout (มิลลิวินาที)
throwOnError boolean ให้ throw error เมื่อสถานะไม่ใช่ 2xx
csrfToken string \| null โทเคน CSRF
interceptors object ตัวดัก request/response

เมธอด

เมธอด HTTP
get(url: string, options?: RequestOptions): Promise<Response>
post(url: string, data?: any, options?: RequestOptions): Promise<Response>
put(url: string, data?: any, options?: RequestOptions): Promise<Response>
delete(url: string, options?: RequestOptions): Promise<Response>
patch(url: string, data?: any, options?: RequestOptions): Promise<Response>
head(url: string, options?: RequestOptions): Promise<Response>
options(url: string, options?: RequestOptions): Promise<Response>
เมธอดโหมดปลอดภัย
getSafe(url: string, options?: RequestOptions): Promise<Response>
postSafe(url: string, data?: any, options?: RequestOptions): Promise<Response>
putSafe(url: string, data?: any, options?: RequestOptions): Promise<Response>
deleteSafe(url: string, options?: RequestOptions): Promise<Response>
เมธอดอื่นๆ
upload(url: string, files: File | File[], options?: UploadOptions): Promise<Response>
request(url: string, options?: RequestOptions): Promise<Response>
เมธอดปรับแต่งค่า
setBaseURL(url: string): void
setDefaultHeader(name: string, value: string): void
setDefaultHeaders(headers: object): void
setTimeout(timeout: number): void
setCsrfToken(token: string): void
เมธอดของ Interceptor
addRequestInterceptor(fn: (config) => config | Promise<config>): () => void
addResponseInterceptor(onFulfilled?: (response) => response, onRejected?: (error) => error): () => void

ยูทิลิตี้ simpleFetch

เมธอด

// HTTP Methods
fetch(url: string, options?: RequestOptions): Promise<Response>
get(url: string, options?: RequestOptions): Promise<Response>
post(url: string, data?: any, options?: RequestOptions): Promise<Response>
put(url: string, data?: any, options?: RequestOptions): Promise<Response>
delete(url: string, options?: RequestOptions): Promise<Response>
patch(url: string, data?: any, options?: RequestOptions): Promise<Response>

// Convenience Methods
json(url: string, options?: RequestOptions): Promise<any>
text(url: string, options?: RequestOptions): Promise<string>
postJson(url: string, data: any, options?: RequestOptions): Promise<any>

// Upload Method
upload(url: string, files: File | File[] | FormData, data?: object, options?: RequestOptions): Promise<Response>

// Configuration Methods
setBaseURL(url: string): simpleFetch
setHeaders(headers: object): simpleFetch
setHeader(name: string, value: string): simpleFetch
setTimeout(timeout: number): simpleFetch
removeHeader(name: string): simpleFetch
resetConfig(): simpleFetch

แนวปฏิบัติที่ดีที่สุด

1. ✅ เลือกใช้ Export ที่เหมาะสม

// ❌ ไม่ดี: ใช้ HttpClient class เมื่อไม่จำเป็น
const client = new HttpClient();
const response = await client.get('/api/users');

// ✅ ดี: ใช้ simpleFetch หรือ http instance
const users = await simpleFetch.json('/api/users');
// หรือ
const response = await http.get('/api/users');

2. ✅ ตั้งค่า Base URL

// ❌ ไม่ดี: URL เต็มทุกครั้ง
await http.get('https://api.example.com/users');
await http.get('https://api.example.com/posts');

// ✅ ดี: ตั้งค่า base URL
http.setBaseURL('https://api.example.com');
await http.get('/users');
await http.get('/posts');

3. ✅ ใช้ Interceptors สำหรับ Common Tasks

// ❌ ไม่ดี: เพิ่ม token ทุกครั้ง
const token = localStorage.getItem('token');
await http.get('/api/users', {
  headers: { 'Authorization': `Bearer ${token}` }
});

// ✅ ดี: ใช้ interceptor
http.addRequestInterceptor(config => {
  const token = localStorage.getItem('token');
  if (token) {
    config.headers['Authorization'] = `Bearer ${token}`;
  }
  return config;
});

await http.get('/api/users');

4. ✅ จัดการ Errors อย่างเหมาะสม

// ❌ ไม่ดี: ไม่ตรวจสอบ response
const response = await http.get('/api/users');
console.log(response.data); // อาจเป็น null

// ✅ ดี: ตรวจสอบ response.ok
const response = await http.get('/api/users');
if (response.ok) {
  console.log(response.data);
} else {
  console.error('ข้อผิดพลาด:', response.statusText);
}

// ✅ ดีกว่า: ใช้ httpThrow
try {
  const response = await httpThrow.get('/api/users');
  console.log(response.data);
} catch (error) {
  console.error('ข้อผิดพลาด:', error.message);
}

5. ✅ ใช้ AbortController สำหรับ Long Requests

// ✅ ดี: สามารถยกเลิกได้
const controller = new AbortController();

button.addEventListener('click', () => {
  http.get('/api/large-data', {
    signal: controller.signal
  });
});

cancelButton.addEventListener('click', () => {
  controller.abort();
});

6. ✅ ระบุ Content-Type ที่ถูกต้อง

// ❌ ไม่ดี: ระบุ Content-Type สำหรับ FormData
await http.post('/api/upload', formData, {
  headers: { 'Content-Type': 'multipart/form-data' }
});

// ✅ ดี: ปล่อยให้ browser ตั้งค่าเอง
await http.post('/api/upload', formData);

7. ✅ เปิดใช้งาน CSRF Protection

// ✅ ดี: เปิดใช้งาน CSRF protection
const client = new HttpClient({
  security: {
    csrf: {
      enabled: true,
      headerName: 'X-CSRF-Token'
    }
  }
});

8. ✅ ตั้งค่า Timeout ที่เหมาะสม

// ❌ ไม่ดี: Timeout เดียวกันทุก request
http.setTimeout(5000);

// ✅ ดี: Timeout ต่างกันตาม request type
http.setTimeout(30000); // Default

await http.get('/api/quick', { timeout: 5000 });
await http.post('/api/process', data, { timeout: 120000 });

9. ✅ Cleanup Interceptors

// ❌ ไม่ดี: ไม่ cleanup
http.addRequestInterceptor(config => {
  // ...
  return config;
});

// ✅ ดี: เก็บ remove function
const removeInterceptor = http.addRequestInterceptor(config => {
  // ...
  return config;
});

// Cleanup เมื่อไม่ต้องการแล้ว
removeInterceptor();

10. ✅ Handle Network Errors

const response = await http.get('/api/users');

if (!response.ok) {
  if (response.status === 0 || response.status === 408) {
    // ไม่สามารถเชื่อมต่อกับเซิร์ฟเวอร์ได้
    alert('Cannot connect to server');
  } else if (response.status >= 500) {
    // เซิร์ฟเวอร์มีปัญหา
    alert('Server error. Please try again later.');
  } else {
    // เกิดข้อผิดพลาด
    alert('An error occurred: ' + response.statusText);
  }
}

สรุป

เลือกใช้ Export ที่เหมาะสม

ถ้าคุณต้องการ... ใช้...
ความเรียบง่าย, เบา simpleFetch
Safe mode (ไม่ throw error) http
Throw errors อัตโนมัติ httpThrow
Custom configuration new HttpClient()

ฟีเจอร์หลัก

ฟีเจอร์ HttpClient http httpThrow simpleFetch
Interceptors
CSRF Protection
Throw on Error ตามที่กำหนด
Custom Handler
Auto Bearer Token
Convenience Methods