Skip to content

Bun 은 서버 측 JavaScript 의 요구를 충족하기 위한 일부 확장 기능과 함께 WHATWG fetch 표준을 구현합니다.

Bun 은 node:http 도 구현하지만 fetch 를 사용하는 것이 일반적으로 권장됩니다.

HTTP 요청 보내기

HTTP 요청을 보내려면 fetch 를 사용합니다.

ts
const response = await fetch("http://example.com");

console.log(response.status); // => 200

const text = await response.text(); // 또는 response.json(), response.formData() 등

fetch 는 HTTPS URL 에서도 작동합니다.

ts
const response = await fetch("https://example.com");

fetchRequest 객체를 전달할 수도 있습니다.

ts
const request = new Request("http://example.com", {
  method: "POST",
  body: "Hello, world!",
});

const response = await fetch(request);

POST 요청 보내기

POST 요청을 보내려면 method 속성이 "POST" 로 설정된 객체를 전달합니다.

ts
const response = await fetch("http://example.com", {
  method: "POST",
  body: "Hello, world!",
});

body 는 문자열, FormData 객체, ArrayBuffer, Blob 등이 될 수 있습니다. 자세한 내용은 MDN 문서 를 참조하세요.

요청 프록시

요청을 프록시하려면 proxy 속성이 URL 문자열로 설정된 객체를 전달합니다.

ts
const response = await fetch("http://example.com", {
  proxy: "http://proxy.com",
});

프록시 서버에 사용자 정의 헤더를 보내기 위해 객체 형식을 사용할 수도 있습니다.

ts
const response = await fetch("http://example.com", {
  proxy: {
    url: "http://proxy.com",
    headers: {
      "Proxy-Authorization": "Bearer my-token",
      "X-Custom-Proxy-Header": "value",
    },
  },
});

headers 는 HTTPS 대상의 경우 CONNECT 요청에서 또는 HTTP 대상의 경우 프록시 요청에서 프록시로 직접 전송됩니다. Proxy-Authorization 헤더를 제공하면 프록시 URL 의 자격 증명을 재정의합니다.

사용자 정의 헤더

사용자 정의 헤더를 설정하려면 headers 속성이 객체로 설정된 객체를 전달합니다.

ts
const response = await fetch("http://example.com", {
  headers: {
    "X-Custom-Header": "value",
  },
});

Headers 객체를 사용하여 헤더를 설정할 수도 있습니다.

ts
const headers = new Headers();
headers.append("X-Custom-Header", "value");

const response = await fetch("http://example.com", {
  headers,
});

응답 본문

응답 본문을 읽으려면 다음 메서드 중 하나를 사용합니다.

  • response.text(): Promise<string>: 응답 본문을 문자열로 해결하는 promise 를 반환합니다.
  • response.json(): Promise<any>: 응답 본문을 JSON 객체로 해결하는 promise 를 반환합니다.
  • response.formData(): Promise<FormData>: 응답 본문을 FormData 객체로 해결하는 promise 를 반환합니다.
  • response.bytes(): Promise<Uint8Array>: 응답 본문을 Uint8Array 로 해결하는 promise 를 반환합니다.
  • response.arrayBuffer(): Promise<ArrayBuffer>: 응답 본문을 ArrayBuffer 로 해결하는 promise 를 반환합니다.
  • response.blob(): Promise<Blob>: 응답 본문을 Blob 으로 해결하는 promise 를 반환합니다.

응답 본문 스트리밍

async 이터레이터를 사용하여 응답 본문을 스트리밍할 수 있습니다.

ts
const response = await fetch("http://example.com");

for await (const chunk of response.body) {
  console.log(chunk);
}

ReadableStream 객체에 더 직접적으로 액세스할 수도 있습니다.

ts
const response = await fetch("http://example.com");

const stream = response.body;

const reader = stream.getReader();
const { value, done } = await reader.read();

요청 본문 스트리밍

ReadableStream 을 사용하여 요청 본문에서 데이터를 스트리밍할 수도 있습니다.

ts
const stream = new ReadableStream({
  start(controller) {
    controller.enqueue("Hello");
    controller.enqueue(" ");
    controller.enqueue("World");
    controller.close();
  },
});

const response = await fetch("http://example.com", {
  method: "POST",
  body: stream,
});

HTTP(S) 에서 스트림을 사용할 때:

  • 데이터는 전체 본문을 메모리에 버퍼링하지 않고 네트워크로 직접 스트리밍됩니다
  • 연결이 손실되면 스트림이 취소됩니다
  • 스트림의 크기를 알 수 없는 경우 Content-Length 헤더가 자동으로 설정되지 않습니다

S3 에서 스트림을 사용할 때:

  • PUT/POST 요청의 경우 Bun 은 자동으로 멀티파트 업로드를 사용합니다
  • 스트림은 청크로 소비되어 병렬로 업로드됩니다
  • 진행 상황은 S3 옵션을 통해 모니터링할 수 있습니다

시간 제한이 있는 URL 가져오기

시간 제한이 있는 URL 을 가져오려면 AbortSignal.timeout 을 사용합니다.

ts
const response = await fetch("http://example.com", {
  signal: AbortSignal.timeout(1000),
});

요청 취소

요청을 취소하려면 AbortController 를 사용합니다.

ts
const controller = new AbortController();

const response = await fetch("http://example.com", {
  signal: controller.signal,
});

controller.abort();

Unix 도메인 소켓

Unix 도메인 소켓을 사용하여 URL 을 가져오려면 unix: string 옵션을 사용합니다.

ts
const response = await fetch("https://hostname/a/path", {
  unix: "/var/run/path/to/unix.sock",
  method: "POST",
  body: JSON.stringify({ message: "Hello from Bun!" }),
  headers: {
    "Content-Type": "application/json",
  },
});

TLS

클라이언트 인증서를 사용하려면 tls 옵션을 사용합니다.

ts
await fetch("https://example.com", {
  tls: {
    key: Bun.file("/path/to/key.pem"),
    cert: Bun.file("/path/to/cert.pem"),
    // ca: [Bun.file("/path/to/ca.pem")],
  },
});

사용자 정의 TLS 유효성 검사

TLS 유효성 검사를 사용자 정의하려면 tls 에서 checkServerIdentity 옵션을 사용합니다.

ts
await fetch("https://example.com", {
  tls: {
    checkServerIdentity: (hostname, peerCertificate) => {
      // 인증서가 유효하지 않은 경우 Error 반환
    },
  },
});

이는 Node 의 net 모듈에서 작동하는 방식과 유사합니다.

TLS 유효성 검사 비활성화

TLS 유효성 검사를 비활성화하려면 rejectUnauthorizedfalse 로 설정합니다.

ts
await fetch("https://example.com", {
  tls: {
    rejectUnauthorized: false,
  },
});

이는 자체 서명된 인증서를 사용할 때 SSL 오류를 피하는 데 특히 유용하지만 TLS 유효성 검사를 비활성화하므로 주의해서 사용해야 합니다.

요청 옵션

표준 fetch 옵션 외에도 Bun 은 여러 확장 기능을 제공합니다.

ts
const response = await fetch("http://example.com", {
  // 자동 응답 압축 해제 제어 (기본값: true)
  // gzip, deflate, brotli (br) 및 zstd 지원
  decompress: true,

  // 이 요청에 대한 연결 재사용 비활성화
  keepalive: false,

  // 디버그 로깅 레벨
  verbose: true, // 또는 더 자세한 출력을 위해 "curl"
});

프로토콜 지원

HTTP(S) 를 넘어 Bun 의 fetch 는 여러 추가 프로토콜을 지원합니다.

S3 URLs - s3://

Bun 은 S3 버킷에서 직접 가져오기를 지원합니다.

ts
// 환경 변수를 사용한 자격 증명
const response = await fetch("s3://my-bucket/path/to/object");

// 또는 명시적으로 자격 증명 전달
const response = await fetch("s3://my-bucket/path/to/object", {
  s3: {
    accessKeyId: "YOUR_ACCESS_KEY",
    secretAccessKey: "YOUR_SECRET_KEY",
    region: "us-east-1",
  },
});

참고: S3 를 사용할 때 PUT 과 POST 메서드만 요청 본문을 지원합니다. 업로드의 경우 Bun 은 스트리밍 본문을 위해 자동으로 멀티파트 업로드를 사용합니다.

Bun 의 S3 지원에 대한 자세한 내용은 S3 문서를 참조하세요.

File URLs - file://

file: 프로토콜을 사용하여 로컬 파일을 가져올 수 있습니다.

ts
const response = await fetch("file:///path/to/file.txt");
const text = await response.text();

Windows 에서 경로는 자동으로 정규화됩니다.

ts
// Windows 에서 둘 다 작동
const response = await fetch("file:///C:/path/to/file.txt");
const response2 = await fetch("file:///c:/path\\to/file.txt");

Data URLs - data:

Bun 은 data: URL 체계를 지원합니다.

ts
const response = await fetch("data:text/plain;base64,SGVsbG8sIFdvcmxkIQ==");
const text = await response.text(); // "Hello, World!"

Blob URLs - blob:

URL.createObjectURL() 로 생성된 URL 을 사용하여 blob 을 가져올 수 있습니다.

ts
const blob = new Blob(["Hello, World!"], { type: "text/plain" });
const url = URL.createObjectURL(blob);
const response = await fetch(url);

오류 처리

Bun 의 fetch 구현에는 여러 특정 오류 사례가 포함됩니다.

  • GET/HEAD 메서드와 함께 요청 본문을 사용하면 오류가 발생합니다 (fetch API 에 예상됨)
  • proxyunix 옵션을 함께 사용하려고 하면 오류가 발생합니다
  • rejectUnauthorized 가 true(또는 정의되지 않음) 일 때 TLS 인증서 유효성 검사 실패
  • S3 작업은 인증 또는 권한과 관련된 특정 오류를 발생시킬 수 있습니다

Content-Type 처리

Bun 은 명시적으로 제공되지 않은 경우 요청 본문에 대해 Content-Type 헤더를 자동으로 설정합니다.

  • Blob 객체의 경우 blob 의 type 사용
  • FormData 의 경우 적절한 multipart boundary 설정

디버깅

디버깅을 돕기 위해 fetchverbose: true 를 전달할 수 있습니다.

ts
const response = await fetch("http://example.com", {
  verbose: true,
});

이것은 요청 및 응답 헤더를 터미널에 출력합니다.

sh
[fetch] > HTTP/1.1 GET http://example.com/
[fetch] > Connection: keep-alive
[fetch] > User-Agent: Bun/1.3.3
[fetch] > Accept: */*
[fetch] > Host: example.com
[fetch] > Accept-Encoding: gzip, deflate, br, zstd

[fetch] < 200 OK
[fetch] < Content-Encoding: gzip
[fetch] < Age: 201555
[fetch] < Cache-Control: max-age=604800
[fetch] < Content-Type: text/html; charset=UTF-8
[fetch] < Date: Sun, 21 Jul 2024 02:41:14 GMT
[fetch] < Etag: "3147526947+gzip"
[fetch] < Expires: Sun, 28 Jul 2024 02:41:14 GMT
[fetch] < Last-Modified: Thu, 17 Oct 2019 07:18:26 GMT
[fetch] < Server: ECAcc (sac/254F)
[fetch] < Vary: Accept-Encoding
[fetch] < X-Cache: HIT
[fetch] < Content-Length: 648

참고: verbose: boolean 은 Web 표준 fetch API 의 일부가 아니며 Bun 에만 해당됩니다.

성능

HTTP 요청을 보내기 전에 DNS 조회를 수행해야 합니다. DNS 서버가 느리거나 네트워크 연결이 좋지 않은 경우 특히 시간이 많이 걸릴 수 있습니다.

DNS 조회 후 TCP 소켓을 연결해야 하며 TLS 핸드셰이크를 수행해야 할 수도 있습니다. 이 또한 시간이 많이 걸릴 수 있습니다.

요청이 완료된 후 응답 본문을 소비하는 데에도 상당한 시간과 메모리가 소요될 수 있습니다.

Bun 은 애플리케이션의 성능을 최적화하는 데 도움이 되는 API 를 모든 단계에서 제공합니다.

DNS 프리페칭

DNS 항목을 프리페치하려면 dns.prefetch API 를 사용할 수 있습니다. 이 API 는 곧 호스트에 연결해야 할 것으로 예상하고 초기 DNS 조회를 피하고 싶을 때 유용합니다.

ts
import { dns } from "bun";

dns.prefetch("bun.com");

DNS 캐싱

기본적으로 Bun 은 DNS 쿼리를 최대 30 초 동안 인메모리에서 캐시하고 중복 제거합니다. dns.getCacheStats() 를 호출하여 캐시 통계를 확인할 수 있습니다.

Bun 의 DNS 캐싱에 대한 자세한 내용은 DNS 캐싱 문서를 참조하세요.

호스트에 사전 연결

호스트에 사전 연결하려면 fetch.preconnect API 를 사용할 수 있습니다. 이 API 는 곧 호스트에 연결해야 할 것으로 예상하고 초기 DNS 조회, TCP 소켓 연결 및 TLS 핸드셰이크를 일찍 시작하고 싶을 때 유용합니다.

ts
import { fetch } from "bun";

fetch.preconnect("https://bun.com");

참고: fetch.preconnect 직후에 fetch 를 호출해도 요청이 더 빨라지지 않습니다. 사전 연결은 곧 호스트에 연결해야 하지만 아직 요청할 준비가 되지 않았을 때만 도움이 됩니다.

시작 시 사전 연결

시작 시 호스트에 사전 연결하려면 --fetch-preconnect 를 전달합니다.

sh
bun --fetch-preconnect https://bun.com ./my-script.ts

이것은 HTML 의 <link rel="preconnect"> 와 비슷합니다.

이 기능은 아직 Windows 에서 구현되지 않았습니다. Windows 에서 이 기능을 사용하고 싶다면 이슈를 제기해 주세요. Windows 에서 지원을 구현할 수 있습니다.

연결 풀링 및 HTTP keep-alive

Bun 은 동일한 호스트에 대한 연결을 자동으로 재사용합니다. 이를 연결 풀링이라고 합니다. 이는 연결 설정에 소요되는 시간을 크게 줄일 수 있습니다. 이를 활성화하기 위해 아무것도 할 필요가 없습니다. 자동으로 수행됩니다.

동시 연결 제한

기본적으로 Bun 은 동시 fetch 요청의 최대 수를 256 으로 제한합니다. 이는 여러 가지 이유로 수행됩니다.

  • 전체 시스템 안정성을 향상시킵니다. 운영 체제는 일반적으로 몇 천 개의 낮은 범위에서 동시 개방 TCP 소켓 수에 상한선이 있습니다. 이 한도에 가까워지면 전체 컴퓨터가 이상하게 작동합니다. 애플리케이션이 멈추고 충돌합니다.
  • HTTP Keep-Alive 연결 재사용을 장려합니다. 수명이 짧은 HTTP 요청의 경우 가장 느린 단계는 종종 초기 연결 설정입니다. 연결을 재사용하면 많은 시간을 절약할 수 있습니다.

한도를 초과하면 요청이 큐에 저장되고 다음 요청이 종료되는 대로 전송됩니다.

BUN_CONFIG_MAX_HTTP_REQUESTS 환경 변수를 통해 동시 연결의 최대 수를 늘릴 수 있습니다.

sh
BUN_CONFIG_MAX_HTTP_REQUESTS=512 bun ./my-script.ts

이 한도의 최대값은 현재 65,336 으로 설정되어 있습니다. 최대 포트 번호는 65,535 이므로 한 컴퓨터가 이 한도를 초과하는 것은 매우 어렵습니다.

응답 버퍼링

Bun 은 응답 본문을 읽는 성능을 최적화하기 위해 최선을 다합니다. 응답 본문을 읽는 가장 빠른 방법은 다음 메서드 중 하나를 사용하는 것입니다.

  • response.text(): Promise<string>
  • response.json(): Promise<any>
  • response.formData(): Promise<FormData>
  • response.bytes(): Promise<Uint8Array>
  • response.arrayBuffer(): Promise<ArrayBuffer>
  • response.blob(): Promise<Blob>

Bun.write 를 사용하여 응답 본문을 디스크의 파일에 쓸 수도 있습니다.

ts
import { write } from "bun";

await write("output.txt", response);

구현 세부 정보

  • 연결 풀링은 기본적으로 활성화되어 있지만 keepalive: false 로 요청별로 비활성화할 수 있습니다. "Connection: close" 헤더를 사용하여 keep-alive 를 비활성화할 수도 있습니다.
  • 대용량 파일 업로드는 특정 조건에서 운영 체제의 sendfile 시스템 호출을 사용하여 최적화됩니다.
    • 파일은 32KB 보다 커야 합니다
    • 요청은 프록시를 사용하지 않아야 합니다
    • macOS 에서 sendfile 은 정규 파일 (파이프, 소켓 또는 장치가 아님) 만 사용할 수 있습니다
    • 이러한 조건이 충족되지 않거나 S3/스트리밍 업로드를 사용하는 경우 Bun 은 파일을 메모리로 읽는 방식으로 폴백합니다
    • 이 최적화는 파일이 커널에서 네트워크 스택으로 직접 전송될 수 있는 HTTP(HTTPS 아님) 요청에서 특히 효과적입니다
  • S3 작업은 자동으로 요청 서명 및 인증 헤더 병합을 처리합니다

참고: 이 기능 중 많은 부분이 표준 fetch API 에 대한 Bun 특정 확장입니다.

Bun by www.bunjs.com.cn 편집