오프체인 HTTP 요청하기

오프체인 워커를 사용하여 HTTP 요청을 하는 방법을 설명합니다.

대부분의 블록체인은 자체 네트워크 외부에 호스팅된 데이터에 접근할 수 없기 때문에, 일반적으로 외부 제3자 서비스인 오라클을 사용하여 네트워크 외부의 위치에서 정보를 가져오거나 정보를 전송합니다. Substrate 기반 블록체인에서는 오프체인 워커(OCW)가 이와 유사한 기능을 제공하지만, 온체인 상태에 접근할 수 있는 장점이 있습니다.

이 가이드에서는 오프체인 워커를 사용하여 GET 또는 POST 메서드를 사용하여 HTTP 요청을 하는 방법을 설명합니다. 이 가이드의 예제에서는 cryptocompare API에서 비트코인 가격을 가져오는 방법과 오프체인 워커 API를 사용하여 데이터를 제출하는 방법을 볼 수 있습니다.

Rust는 HTTP 요청을 보내기 위한 자체 라이브러리를 제공한다는 것을 알 수 있습니다. 그러나 오프체인 워커는 자체 WebAssembly 실행 환경인 no-std 환경에서 실행되므로 표준 Rust 라이브러리에 액세스할 수 없습니다. 대신, Substrate는 HTTP 요청을 보내기 위해 사용할 수 있는 자체 라이브러리를 제공합니다.

Substrate HTTP 라이브러리는 다음과 같은 메서드를 지원합니다:

  • GET

  • POST

  • PUT

  • PATCH

  • DELETE

데드라인 설정 및 HTTP 요청 인스턴스화

대부분의 경우, 오프체인 워커가 작업을 실행하는 데 허용되는 시간을 제한하고 싶을 것입니다. 이 예제에서는 외부 호출을 완료하기 위해 2초의 하드 코딩된 데드라인을 설정할 수 있습니다. 또한 응답을 무기한으로 기다릴 수도 있습니다. 그러나 무기한으로 기다리는 것은 외부 호스트 머신에서 타임아웃이 발생할 수 있습니다.

  1. 2초의 데드라인을 생성합니다.

    let deadline = sp_io::offchain::timestamp().add(Duration::from_millis(2_000));
  2. 외부 HTTP GET 요청을 시작합니다.

    let request = http::Request::get("https://min-api.cryptocompare.com/data/price?fsym=BTC&tsyms=USD");
    let pending = request.deadline(deadline).send().map_err(|_| http::Error::IoError)?;
    let response = pending.try_wait(deadline).map_err(|_| http::Error::DeadlineReached)??;

응답 읽기 및 제출하기

  1. 응답 상태 코드를 확인합니다.

    // 응답을 읽기 전에 상태 코드를 확인해 봅시다.
    if response.code != 200 {
      log::warn!("예상하지 못한 상태 코드: {}", response.code);
      return Err(http::Error::Unknown)
    }
  2. 응답을 읽습니다.

    let body = response.body().collect::<Vec<u8>>();
    // 바디에서 str 슬라이스를 생성합니다.
    let body_str = sp_std::str::from_utf8(&body).map_err(|_| {
      log::warn!("UTF8 바디 없음");
      http::Error::Unknown
    })?;
  3. POST 요청을 사용하여 API에 데이터를 제출합니다.

     // POST 요청 보내기
    let request_body = Vec::new();
    let request = http::Request::post("https://reqres.in/api/users", vec![request_body.clone()])
      .add_header("x-api-key", "test_api_key")
      .add_header("content-type", "application/json");
    
    let pending = request
      .deadline(deadline)
      .body(vec![request_body.clone()])
      .send()
      .map_err(|_| http::Error::IoError)?;
    
    // 응답 기다리기
    let response = pending
      .try_wait(deadline)
      .map_err(|_| http::Error::DeadlineReached)??;

예제

Last updated