[튜토리얼] RAD 서버를 활용해 데이터를 REST API로 서비스하기

2021. 12. 14. 09:30

제가 진행한 온라인 세미나-WHAT’S NEW! RAD스튜디오 11 중 세션 2-1의 다시보기, 자료, 따라하기입니다.

 

샘플 데이터베이스(InterBase-FishFacts)의 데이터를 REST API로 서비스하는 과정을 익히고, 여러분의 데이터에도 적용할 수 있습니다.

<핵심>

  • TEMSDataSetResource 컴포넌트(몇가지 속성 설정만으로): 데이터베이스 데이터를 REST API로 서비스하는 리소스 추가
  • 커스텀 엔드포인트 작성: 이미지 제공과 같은 로직이 포함된 엔드포인트

1. 준비하기

RAD 서버 환경설정(최초 사용 시)

이 따라하기는 RAD 서버를 이용해 REST API를 제공합니다. RAD 서버를 처음 사용하는 경우 "RAD 서버 개발환경 설정하기(준비 중)"를 참고해 설정합니다.

샘플 데이터 파일 다운로드

이 따라하기는 인터베이스 용 "Fish facts(어류도감) 데이터"를 샘플 데이터로 사용합니다. 다음 링크에서 [Download] 버튼을 눌러 적절한 경로에 다운로드 합니다.

https://github.com/devgear/FishFactsRSX/blob/main/Data/BIOLIFE.IB

 

2. RAD 서버 패키지 프로젝트 생성하기

  1. IDE를 열고, File > New > Other 메뉴 클릭
  2. Delphi > RAD Server > RAD Server Package 선택 > [OK] 버튼 클릭

     
  3. 리소스를 포함한 패키지 생성
    "Create package with resource" 선택 > [Next >>] 버튼 클릭
     
  4. 리소스 이름 입력 및 파일 타입을 데이터 모듈로 선택(논비주얼 컴포넌트 사용에 필요)
    Resource name "fishfacts" 입력 > File type "Data Module" 선택 > [Next >>] 버튼 클릭
     
  5. 샘플 엔드포인트에서 이미지 제공에 사용할 GetItem만 선택
    GetItem만 선택 > [Finish] 버튼 클릭
    • Sample Endpoints: 프로젝트 생성 시 선택한 커스텀 엔드포인트 메소드 코드 자동 생성
    • Database Endpoints: 사전 정의된 데이터베이스 연결의 테이블을 선택 해 데이터를 제공하는 리소스 자동 생성
      (이 따라하기에서는 이 과정을 수작업으로 진행)
    • API Documentation: 코드를 이용해 Swagger API 문서 제공
       
  6. 프로젝트 생성 완료
  7. (선택사항) 프로젝트 저장
    • 프로젝트 파일: FishfactsPackage.dproj
    • 유닛 파일: BiolifeResource.pas
    • (다른이름(및 형식)의 파일명으로 저장해도 문제 없음)

3. 데이터베이스 연결하기

"1, 사전 준비하기" 단계에서 다운로드 받은 인터베이스 데이터베이스와 연결합니다.

참고> 이 따라하기에서는 인터베이스 데이터베이스와 연결하지만, 다른 DBMS와 연결해도 됩니다.

참고> 이 따라하기에서는 FireDAC을 이용해 데이터베이스와 연결하지만, 다른 데이터 엑세스 컴포넌트를 사용해도 됩니다.

  1. 데이터베이스 연결
    1. TFDConnection 컴포넌트를 데이터 모듈에 추가
    2. 추가된 TFDConnection 컴포넌트를 더블클릭해 "FireDAC Connection Editor" 표시
       
    3. 데이터 연결 속성 설정
      • Driver ID: IB 선택
      • Database: 다운로드 받은 "BIOLIFE.IB" 파일 선택
      • User_Name: sysdba 입력
      • Password: masterkey 입력
      • [Test] 버튼 클릭해 연결 확인
      • [OK]버튼 클릭
    4. Object Inspector에서 TFDConnection의 LoginPrompt 속성을 "False"로 변경
  2. 쿼리 설정
    1. TFDQuery 컴포넌트를 데이터 모듈에 추가
    2. 추가된 TFDQuery 컴포넌트를 더블클릭해 "FireDAC Query Editor" 표시
       
    3. SQL 조회 문구 입력
      SELECT * FROM BIOLIFE
    4. [Execute] 버튼 클릭 후 데이터 확인
    5. [OK] 버튼 클릭

 

4. 데이터를 REST API 리소스로 제공하도록 설정하기

앞에서 추가한 데이터셋의 데이터를 HTTP 기반 REST API로 제공하도록 설정하고, 이미지 제공을 위한 커스텀 엔드포인트를 설정합니다.

데이터 제공 용 TEMSDataSetResource 컴포넌트 설정

TEMSDataSetResource 컴포넌트(10.3 리오에서 추가)를 이용해 리소스를 추가합니다.

TEMSDataSetResource 컴포넌트는 DataSet 속성에 설정된 데이터셋의 데이터를 REST API로 제공합니다.
리소스에 HTTP 메소드(Get, Post, Put, Delete) 요청 시 데이터 제공(조회) 및 처리(등록, 수정, 삭제)를 자동화 해줍니다.

  1. TEMSDataSetResource 컴포넌트를 데이터 모듈에 추가
  2. (Object Inspector에서)AllowAcctions 속성 모두 선택
    • List: 데이터셋 목록 제공
    • Get: 특정 항목 제공
    • Post: 신규 항목 생성
    • Put: 특정 항목 수정
    • Delete: 특정 항목 제거
       
  3. 데이터셋 설정
    DataSet 속성에 앞에서 추가한 TFDQuery 컴포넌트 선택
     
  4. 키필드 설정
    • KeyFIelds 속성 더블클릭
    • SPECIES_NO 선택 후 [>] 버튼을 클릭해 "Included fields:"로 이동
    • [OK] 버튼 클릭
       
  5. API로 제공할 필드 선택
    • ValueFIelds 속성 더블클릭
    • 용량이 큰 GRAPHIC(Blob Field) 제외한 모든 항목을 "Included fields:"로 이동
    • [OK] 버튼 클릭
       
  6. 리소스 이름 지정
    • 코드 에디터로 변경(F12)
    • TEMSDataSetResource 선언부 위에 리소스 이름 특성 추가
          [ResourceName('biolifes')]
          EMSDataSetResource1: TEMSDataSetResource;

이미지 제공 커스텀 엔드포인트 추가

이미지 제공 등 큰 용량의 데이터 제공은 별도의 엔드포인트로 제공해야 합니다.

샘플 엔드포인트로 생성한 GetItem에 Blob 필드에 저장된 이미지를 제공하도록 구현합니다.

  1. 그래픽 조회 용 쿼리 컴포넌트 추가
    1. TFDQuery 컴포넌트를 데이터 모듈에 추가(FDQuery2)
    2. 추가된 TFDQuery 컴포넌트를 더블클릭해 "FireDAC Query Editor" 표시
       
    3. SQL 조회 문구 입력
      SELECT GRAPHIC FROM BIOLIFE WHERE SPECIES_NO = :ITEM
    4. [OK] 버튼 추가
       
  2. 커스텀 엔드포인트 수정
      1. GetItem 선언부 위에 리소스 접미사 변경
            [ResourceSuffix('bio/lifes/{item}/photo/')]
            procedure GetItem(const AContext: TEndpointContext; const ARequest: TEndpointRequest; const AResponse: TEndpointResponse);
      2. 엔드포인트 호출 시 이미지 제공하도록 구현부 변경
    procedure TFishfactsResource1.GetItem(const AContext: TEndpointContext; const ARequest: TEndpointRequest; const AResponse: TEndpointResponse);
    var
      item: string;
      Stream: TMemoryStream;
    begin
      item := ARequest.Params.Values['item'];
      Stream := TMemoryStream.Create;
      try
        FDQuery2.Close;
        FDQuery2.ParamByName('item').AsString := item;
        FDQuery2.Open;
    
        if FDQuery2.RecordCount = 0 then
          AResponse.RaiseNotFound('Not found', '''' + item + ''' is not found');
    
        TBlobField(FDQuery2.FieldByName('GRAPHIC')).SaveToStream(Stream);
    
        if Stream.Size = 0 then
          AResponse.RaiseNotFound('Not found', '''' + item + ''' is not found');
    
        Stream.Position := 0;
        AResponse.Body.SetStream(Stream, 'image/jpeg', True);
      except
        Stream.Free;
        raise;
      end;
    end;

5. RAD 서버 실행 및 결과 확인

RAD 서버 실행

RAD 서버는 패키지를 개발해 RAD 서버 엔진을 이용해 패키지를 로드하는 방식입니다.
(개발한 프로젝트의 확장자는 *.bpl(Boload Package Library))

개발 시점에는 RAD Development Server를 실행해 결과 확인과 테스트를 진행합니다.
운영서버에서는 "Microsoft IIS" 및 "Apache Server" 엔진을 이용하는 것이 좋습니다.(운영환경에서 RAD 서버 엔진 설치(영문) 참조)

  1. 프로젝트 실행(F9)
  2. (최초 1회) 필요 패키지 추가
    아래와 같은 대화상자 표시된 경우 [OK] 버튼 클릭
    • FireDAC에서 사용하는 패키지 추가
       
  3. RAD Development Server 실행 및 로그 확인
    • 빨간색 로그
      {"Thread":1812,"Loading":{"Filename":"C:\Users\Public\Documents\Embarcadero\Studio\22.0\Bpl\FishfactsPackage.bpl"}}
      • 우리가 생성한 RAD 서버 패키지가 로드 된 것을 확인
         
    • 주황색 로그
      {"Thread":1812,"RegResource":{"name":"fishfacts","endpoints":[
        {"name":"GetItem","method":"Get","path":"fishfacts/bio/lifes/{item}/photo/"},
        {"name":"biolifes.List","method":"Get","path":"fishfacts/biolifes/","produce":"application/json, *;q=0.9"},
        {"name":"biolifes.Get","method":"Get","path":"fishfacts/biolifes/{id}","produce":"application/json, *;q=0.9"},
        {"name":"biolifes.Put","method":"Put","path":"fishfacts/biolifes/{id}","consume":"application/json, *;q=0.9"},
        {"name":"biolifes.Post","method":"Post","path":"fishfacts/biolifes/","consume":"application/json, *;q=0.9"},
        {"name":"biolifes.Delete","method":"Delete","path":"fishfacts/biolifes/{id}"}
      ]}}
      • GetItem: 이미지 제공을 위한 커스텀 엔드포인트 제공한 것을 확인
      • biolifes.{Actions}: TEMSDataSetResource에서 제공하는 액션 제공한 것을 확인
         

웹브라우저에서 결과확인

  1. 웹브라우저에서 List 액션 결과 확인
    1. 웹브라우저 실행 후 주소에 다음 URL 입력 후 실행
      http://localhost:8080/fishfacts/biolifes/
       
    2. 결과 확인
      (FireFox에서 확인 시)
  2. 웹브라우저에서 이미지 제공 결과 확인
    1. 웹브라우저 실행 후 주소에 다음 URL 입력 후 실행
      http://localhost:8080/fishfacts/biolifes/90020/photo/

       
    2. 결과 확인
      (FireFox에서 확인 시)

험프리.김현수 Delphi/C++Builder

[번역] RAD Studio 11의 새로운 RAD 서버 라이트(RSLite)

2021. 12. 14. 09:18

마르코 칸투(Marco Cantu)의 The New RAD Server Lite (RSLite) in RAD Studio 11을 번역했습니다.

RAD 스튜디오 11 알렉산드리아 출시와 함께, RAD 서버 배포/라이선스에 라이트(Lite) 버전이 새로 추가되었다. 이것은 REST 요청이 많지 않은, 배포/설치가 보다 간소화된 RAD 서버이다. 

RAD 서버는 무엇인가?

세부 사항에 앞서 RAD 서버가 무엇인지 살펴 보자. RAD 서버는 REST 서버 엔진이다. 개발자는 REST 엔드포인트 (주로 JSON을 제공)를 빠르게 개발할 수 있다. 개발 도구는 델파이 또는 C++빌더를 사용하며 FireDAC(또는 다른 데이터 엑세스 레이어)를 사용하여 데이터에 연결한다. 정리하면, 개발자가 애드온 패키지(BPL)를 만들고, 이것에 URL 엔드포인트를 등록하는 방식으로 원하는 서비스를 구현/제공한다. RAD 서버에는 이처럼 개발자가 직접 구현할 수 있는 능력 뿐만 아니라 일반적인 서비스들이 바로 사용할 수 있도록 미리 구현되어 있다 (자세한 내용: https://www.embarcadero.com/products/rad-server).

RAD 서버 라이트(Lite)가 왜 추가 되었는가?

RAD 서버는 서버 데이터를 관리하는 데이터베이스(InterBase)가 백엔드에서 작동한다. 그리고, RAD 서버는 웹서버 DLL 모듈 형태로 IIS 또는 Apache에 배포되는 것이 일반적이다.

따라서, 표준 배포를 하려면, 아래 사항이 필요하다.

  • 웹 서버를 작동하고, 그 웹 서버에 "RAD 서버 모듈"을 구성
  • RAD 서버를 배포하고 구성
  • InterBase를 설치하고 RAD 서버 전용 InterBase 라이선스를 등록 (RAD서버를 배포되는 장비에 이 라이선스를 등록해야 사용할 수 있다)

개발용 독립 실행 버전인, "RAD 서버 개발자 에디션"이 제공된 지는 이미 꽤 오래되었다. RAD 서버 개발자 에디션은 Indy HTTP 서버 기반이므로 성능에 제한이 있다. 하지만 배포가 훨씬 쉽고, 디버거 안에서도 실행될 수 있다 (덕분에 개발자는 RAD 서버 모듈의 코드를 디버깅할 수 있다). 개발자 버전이라고 해서 배포를 허용하지 않는 것은 아니다. 다만, 사용자 수에 제한이 있으며, 데이터베이스로는 (RAD 스튜디오 라이선스에 포함되어 있는) "InterBase 개발자 에디션"이 사용된다.

RAD 서버 라이트(일명 RSLite)는 배포 모델이 더 간단하며, 용도는 테스트 서버 또는 처리량이 많지 않은 시나리오에 적합하다. RSLite에서 사용되는 InterBase 데이터베이스는 모든 기능을 갖춘 서버 버전이 아니라 임베디드 엔진인 IBToGo가 사용되며, 라이선스 모델도 더 단순하다. RSLite는 "RAD 서버 개발자 에디션(RAD 스튜디오와 함께 제공됨)"과 동일한 바이너리, IBToGo 바이너리, 라이선스 슬립파일을 사용하므로, 한번에 솔루션과 함께 배포할 수 있다 (즉 배포할 컴퓨터에서 따로 등록할 필요가 없다)

임베디드 데이터베이스와 IndyHTTP 서버 컴포넌트를 사용하기 때문에, 일반적인 RAD 서버에 비해 초당 요청 처리 능력이 떨어지고, 프론트 엔드에 RAD 서버를 여러대 추가하는 방식으로 확장하지 못한다는 단점이 있다. 우리가 별도 작업을 통해 기능을 제약하지는 않았지만, 기반 아키텍처 상 RSLite의 확장성은 매우 제한적이다. 하지만, 단순한 시나리오에서 사용하기에는 충분할 것이다. 단, 처리 능력은 RAD 서버 모듈에서 실행되는 코드 즉 개발자가 구현한 코드에 따라 달라진다는 점을 명심해야 한다. 외부에 공개되는 시스템에 배포할 때에는 RSLite HTTP 서버를 외부로 직접 노출하지 말고, 프록시 통해서 접근하도록 구성하기를 강력히 권장한다. 이렇게 (Apache, IIS와 같은) 웹서버를 앞에 배치함으로써, 인바운드 HTTPS 호출을 RSLite로 포워딩하기 전에 보안 컨텍스트를 제공할 수 있기 때문이다.

라이선스 요청/확보 하기

이제 RSLite를 실제로 어떻게 하면 되는 지를 알아보자. 가장 먼저, 라이선스를 확보해야 한다. 개발 도구인 RAD 스튜디오 11(델파이 11 및 C++빌더 11 포함)의 엔터프라이즈 또는 아키텍트 라이선스를 가지고 아래 페이지의 안내를 따라 진행하면 RSLite 라이선스를 받을 수 있다.

https://reg.embarcadero.com/srs6/promotion.jsp?promoId=572

개발 도구의 등록 키(시리얼번호)와 EDN 계정을 미리 준비하고 진행하자. 이 절차를 모두 마치고 나면 RSLite 라이선스 키와 해당 슬립파일 (라이선스가 기록된 .TXT)을 받게 된다. 슬립 파일은 RAD 서버를 설치할 때 함께 배포하기 위한 라이선스 파일이다. 이 라이선스는 설치 횟수 제한이 없다 (그러나 동일한 컴퓨터에 인스턴스를 2개를 실행할 수는 없다).  라이선스 파일은 특정 하위폴더에 배치해야 한다(아래에 설명을 참고할 것, 라이선스를 확보한 웹페이지에 있는 설명과는 다르니 주의 바람).

RAD 서버 라이트 프로젝트 배포하기

이제 라이선스를 확보했으니, RSLite를 배포하자. 다음 두가지를 알아 두어야 한다.

  • 첫번째로, RSLIte의 배포 구성, 필요한 런타임 패키지, IBToGo 배포를 만들어야 한다(아래에서 절차 설명)
  • 두번째로, 데이터베이스 파일을 만들 때에는 운영 시 사용할 IBToGo 라이선스와 호환되는 파일을 만들어야 한다. — RAD 서버 개발자 에디션에서 생성한 로컬 데이터베이스는 호환되지 않는다.

배포할 파일

RSLite 솔루션을 배포하기 위해 필요한 파일 목록 (실제로는, 당신이 만든 애플리케이션 패키지와 해당 의존 파일들을 아래 파일들과 함께 배포하게 된다) 

  1. RSLite 실행 파일 (RAD 서버 개발자 에디션과 동일한 파일): EMSDevServer.exe는 RAD 스튜디오 bin 폴더에 들어 있다(또는 비슷한 64-비트 버전)
  2. 필수 RAD 스튜디오 런타임 패키지(최소 설치에 필요한 패키지로써 RAD Studio win32 또는 win64 redist 폴더에 들어 있다),
    그리고 당신이 작성한 RAD 서버 모듈 코드에서 참조하는 런타임 패키지: 
    • bindengine280.bpl
    • dbrtl280.bpl
    • emsclientfiredac280.bpl
    • emsserverapi280.bpl
    • FireDAC280.bpl
    • FireDACCommon280.bpl
    • FireDACCommonDriver280.bpl
    • FireDACIBDriver280.bpl
    • rtl280.bpl
    • vcl280.bpl
    • vcldb280.bpl
    • vclFireDAC280.bpl
    • vclimg280.bpl
    • vclwinx280.bpl
    • vclx280.bpl
    • Xmlrtl280.bpl
  3. InterBase ToGo 배포 파일들, 공용문서의 InterBase redist 폴더(예, C:/Users/Public/Documents/Embarcadero/Interbase/redist/InterBase2020) 아래의 win32_togo 또는 win64_togo 폴더 안에 있다 — 리눅스 배포용 파일은 알맞은 InterBase redist 폴더에 있는 libibtogo.so 파일이다.
  4. 앞에서 확보한 라이선스 파일을 interbase/license 폴더 안에 넣는다.

MSVC 런타임

또한 IBToGo (RSLite는 IBToGo를 사용한다)가 작동하려면 배포할 윈도우 시스템에 Visual C++ 2013 런타임 라이브러리가 설치되어 있어야 한다. RAD 스튜디오가 설치된 개발자 컴퓨터라면 이미 설치되어 있을 가능성이 크다. 그러나 일반적인 시스템이라면 아마도 Microsoft에서 다운로드하여 설치해야 할 것이다.

운영 환경에서 사용할 데이터베이스 생성

앞에서 명시된 서버 구성을 모두 마치고 나면, EMSDevServer.exe 애플리케이션을 실행하여 RSLite를 시작하면 된다. 이때 대상 컴퓨터에 InterBase 클라이언트가 설치되어 있으면 이것이 IBLite보다 더 우선하여 선택된다. 그리고 그 InterBase 클라이언트가 RAD 스튜디오와 함께 제공된 "InterBase 개발자 버전"인 경우라면, 모든 동작이 잘 되지만 RSLite가 아니라 표준 RAD 서버의 개발자 에디션으로 작동하게 된다.

이점은 쉽게 파악할 수 있다. RAD 서버가 시작되면 로그에 “RSLite” 구성인지 아닌 지를 기록하기 때문이다. 처음 몇줄은 다음과 같다.

{“Thread”:19124,”ConfigLoaded”:{“Filename”:”[folder]emsserver.ini”,”Exists”:true}}
{“Thread”:19124,”Licensing”:{“Lite”:true,”Licensed”:true,”LicensedMaxUsers”:2}}
{“Thread”:19124,”DBConnection”:{“InstanceName”:””,”Filename”:”[folder]emsserver.ib”}}

만약 로그에 “Lite”가 false라고 기록되어 있다면, InteBase 클라이언트 라이브러리인 gds32.dll이 로딩되지 않도록 하는 조치를 직접해야 한다. 이 파일은 일반적으로 C:\Windows\SysWOW64 폴더에 들어 있다. (RSLite는 표준 RAD 서버와 마찬가지로 기동하면서, 이 폴더에서 InteBase 클라이언트 라이브러리를 찾으려고 한다. 따라서 이 폴더에 gds32.dll 파일을 없어야만, RSLite 안에서 ibtogo.dll를 찾아서 로딩한다. 이와 관련된 보강은 다음 릴리즈에 반영할 예정이다)

구성도 잘 마쳤고 RSLite도 잘 기동했는데,  emsserver.ini 파일과 emsserver.ib 데이터베이스 파일을 새로 만들라는 메시지가 표시되고, "RAD Server Setup Wizard"가 실행되어 이 파일들을 만들 수 있다. 하지만 이 마법사를 실행하려면 RAD 스튜디오 Object Repository 폴더의 설정 파일들이 필요하다. 개발자 PC의 (RAD 스튜디오 설치 경로)/ObjRepos/en/EMS 폴더의 파일들을 배포 환경의 EMSDevServer.exe 기준 ../ObjRepos/en/EMS 폴더로 복사해야 한다.

(역자 주: 만약, D:\RSLite\bin\EMSDevServer.exe가 설치되어 있다면
개발자 PC의 RAD 스튜디오 Object Repository 폴더 하위의 en/EMS 폴더의 파일들을 D:\RSLite\ObjRepos\en\EMS 폴더에 복사해야 합니다.)

참고: 위 작업은 매번 RSLite 배포마다 진행하지 않아도 된다. 최초 1회 프로덕션 데이터베이스 생성을 위해 위 작업을 진행하고, 다음 배포시에는 생성한 프로덕션 데이터베이스를 복사해 사용할 수 있다. 개발환경에서 InterBase 개발자 에디션 기반으로 생성한 데이터베이스는 RSLite와 호환되지 않기 때문이다.

마법사에서 emsserver.ini 파일과 emsserver.ib 데이터베이스 파일 생성 시 RSLite와 동일한 폴더를 지정하는 것을 권장한다.

이제 RSLite, 설정파일, 런타임 패키지 및 라이선스, IBToGo를 모두 백업 받는다. 이제 윈도우 컴퓨터에 배포할 모든 파일들이 준비되었다.(역자 주: 다음 배포 시에는 백업 받은 파일들을 그대로 배포하면 됩니다.)

프록시 구성

앞서 언급했듯 RSLite는 보호 및 암호화 측면에서 제한이 있기 때문에 공개 웹 애플리케이션으로 직접 노출하지 않는 것이 좋다. RSLite 앞단에 프록시 레이어 전용 서비스를 사용하거나, 인기 있는 웹 서비스를 배치하는 것을 권장한다. 예를 들어 Apache에서 가상 호스트 구성 시 HTTPS를 활성화하고, 다음과 같이 구성해 트래픽을 RSLite로 리다이렉션한다.

ProxyPass / http://localhost:8088
ProxyPassReverse / http://localhost:8088
ProxyPreserveHost On

리눅스

리눅스의 경우 위와 비슷한 절차를 진행할 수 있으며, 대부분 예상대로 작동할 것이다. 또한 전체 RAD 서버를 설치하고 나서, IBToGo를 추가도 가능하다.

  • RAD 서버 폴더에 있는 ems_install.sh를 사용해 RAD 서버 설치
(https://docwiki.embarcadero.com/RADStudio/en/Configuring_Your_RAD_Server_Engine_or_RAD_Server_Console_on_Linux)(역자 주: 이 도움말의 내용 중 개발 도구가 설치된 폴더 위치는 버전 별로 다를 수 있다. 예를 들어 19.0 이라는 폴더가 없으면, 22.0 등 내가 설치한 버전에 해당하는 폴더라고 이애하면 된다)
  • InterBase "redist" 폴더(예. C:\Users\Public\Documents\Embarcadero\InterBase\redist\InterBase2020\linux64_togo)의 IBToGo 파일들을 Linux의 EMS 폴더(/usr/lib/ems)로 복사
  • EMSDevServerCommand를 실행하고 마법사를 따라 EMS 데이터베이스 및 구성 파일 생성 (애플리케이션을 실행할 권한이 없다면, 슈퍼 유저로서 실행하기 위해 명령어 앞에 'sudo'를 붙여야 할 수도 있음)

전체 기능이 포함된 RAD 서버로 업그레이드

마지막으로 RSLite는 감당할 수 있는 사용자 요청 트래픽에 한계가 있다는 점을 상기한다. RSLite 보다 더 넓은 대역 폭과 처리량이 필요하다면, 일반 RAD 서버를 배포하는 것이 좋다. RAD 스튜디오, 델파이 또는 C++빌더의 엔터프라이즈 에디션을 구입하고 받는 ESD 라이선스 이메일에는 서버 한 대에 배포할 수 있는 일반 RAD 서버  라이선스가 들어있다. 아키텍트 에디션의 ESD 라이선스 이메일에는 RAD를 서버 여러대에 배포할 수 있는 라이선스가 들어있다. 배포한 RAD 서버가 작동하려면 장비 별로 라이선스를 활성화해야 한다. 당사 영업팀에 문의하여 VAR(Value Added Reseller) 계약을 체결하면 라이선스 슬립파일을 사용하여 별도의 등록 과정 없이도 모든 기능이 있는 일반 RAD 서버를 쉽게 배포할 수도 있다.

험프리.김현수 RAD Studio 정보

[RX.11] REST 클라이언트 Post 전송 시 Get으로 파라미터 전송 이슈 해결방안

2021. 12. 14. 09:12

데브기어 포럼에 등록된 이슈 공유합니다.

https://welcome.devgear.co.kr/topic/227-delphi-11-rest-client-동작-오류-문의드립니다/

 

<질문 요약>

11.0에서 REST 클라이언트로 post로 요청시, 서버단에서 post로 못받고 get으로 인지를 하는 문제입니다. 

개요 : 10.4.2 에서 잘 되던 앱이 11 버전 RestClient POST 방식에서 문제가 되어 여러가지 테스트 해본 결과 POST로 파라미터를 요청을 하면 서버쪽에서 POST로 파라미터 값을 못 받는 현상입니다.

 

<답변>

질문하신 내용을 요약하면 "델파이 11에서 POST로 요청 시 GET으로 메소드를 호출되는 이슈가 있다.로 이해됩니다.

질문의 답변에 앞서,

요구사항을 확인하면 "이미지 데이터를 서버로 전달"하는 것으로 보여 다음 2가지 답변을 드립니다.

1) POST 요청 시 GET으로 호출하는 원인 확인 및 조치사항(질문에 대한 답변)

2) REST 클라이언트로 이미지를 업로드하는 방안(요구사항 솔루션)

 

1) POST 요청 시 GET으로 호출하는 원인 확인 및 조치사항

우선 현상과 원인 파악을 위해 PHP 페이지를 다음과 같이 작성 후 다시 시도해보시기 바랍니다.(정확히 어떤 메소드로 호출하는지 확인할 수 있습니다.)

<?php
$GetId = $_GET['id'];
$PostId = $_POST['id'];

echo $_SERVER["REQUEST_METHOD"]."<br />\n"; // HTTP 메소드(GET / POST)

echo "Get : ".$GetId."<br />\n";
echo "Post : ".$PostId."<br />\n";

echo "body: ".$HTTP_RAW_POST_DATA."<br />\n";
echo "body: ".file_get_contents("php://input")."<br />\n";
?>

제가 테스트한 결과는 다음과 같습니다.

두가지 버전 모두 POST로 요청함을 확인했습니다.
(응답 Body의 첫번째 항목은 HTTP 메소드 종류이며, 둘다 POST로 출력되었습니다.)

하지만 전송한 요청 파라미터(GETorPOST 파라미터)는, 10.4.2에서는 POST($_POST) 데이터로 11.0에서는 GET($_GET)으로 전달됩니다.
결과적으로, 두 버전간 전달하는 방식에 차이가 있는 것을 확인했습니다.

 

두 버전이 다른 결과가 나온 내용을 소스코드에서 분석한 내용을 설명합니다.(간단히 설명하니 참고만 하고, 아래의 결론의 내용을 적용하시기 바랍니다.)
11.0에서 REST 클라이언트의 주요 변경사항 중 ContentType을 문자열로 처리하도록 개선되었습니다.(상당히 많은 양의 코드가 변경되었습니다.)

특히, 파라메터 전송 방식을 판단하는 IsQueryParam은 아래와 같이 변경되었습니다.(좌: 10.4.2, 우: 11.0)

빨간 박스를 보면 파라메터의 컨텐트타입(APram.ContentType)이 ctNone(공백)인 경우 쿼리 파라메터로 인식되어 요청시 Get 형식의 파라메터가 전송됩니다.

위 로직을 피하기 위해서는 다음과 같은 조치를 취해야 합니다.

  1. TRESTRequest.Params 속성 선택
  2. POST 파라메터로 전달하려는 파라메터의 ContentTypeStr을 "multipart/form-data" 지정

위와 같이 지정 후 REQUEST 실행하면 다음과 같이 10.4.2와 동일한 방식으로 POST 파라메터로 전송되는 것을 확인할 수 있습니다.

해당 조치는 REST Debugger에서는 진행할 수 없으니, 소스코드 상에서 조치해야 합니다.

결론: 

델파이 11.0에서 POST 요청 시 파라메터를 POST 파라미터로 전달하려면, 파라메터의 ContentTypeStr을 "multipart/form-data"로 지정해야 합니다.

 

2) REST 클라이언트로 이미지를 업로드하는 방안

이미지를 Base64로 인코딩해 문자열로 전송하셨습니다.  멀티파트 폼데이터(multi-part/formdata)로 전송하는 방식도 검토해 보시기 바랍니다.

멀티파트 폼데이터로 전송 시 Stream을 그대로 파라미터로 설정할 수 있습니다.

다음은 클라이언트에서 멀티파트-폼데이터로 전송하는 샘플 코드입니다.
(파라미터에 파일(pkFILE)이 포함된 경우 multi-part/formdata로 전송됩니다.)

var
  Stream: TMemoryStream;
  Item: TRESTRequestParameter;
begin
  if not OpenDialog1.Execute then
    Exit;

  Stream :=  TMemoryStream.Create;
  Stream.LoadFromFile(OpenDialog1.FileName);

// 파라메터는 디자인타임에 생성되었습니다.
//  Item := RESTRequest1.Params.AddItem;
//  Item.Name := 'img';
//  Item.Kind := pkFILE;
  RESTRequest1.Params.ParameterByName('img').SetStream(Stream);

  RESTRequest1.Method := rmPOST;
  RESTRequest1.Execute;
end;

멀티파트 폼데이터로 전송 시 웹서버에서 파일 전송과 동일한 방식으로 받아 처리할 수 있습니다.

RAD 서버 11.0에서는 다음 코드를 이용해 멀티파트 폼데이터를 처리할 수 있습니다.

procedure TImgResource1.Post(const AContext: TEndpointContext; const ARequest: TEndpointRequest; const AResponse: TEndpointResponse);
var
  Stream: TStream;
begin
  Stream := ARequest.Body.GetPart('img', '').GetStream;

  if Stream.Size <= 0 then
    AResponse.RaiseBadRequest('no stream');

  TMemoryStream(Stream).SaveToFile('D:\Temp\test.jpg');
end;

위 샘플코드 프로젝트입니다.

RSX_FileUpload.zip
0.01MB

 

결론: 
이미지 등의 파일 업로드 구현 시 멀티파티 폼데이터로 전송할 수도 있습니다.
(델파이의 일반적인 데이터구조인 Stream을 바로 전송할 수 있어 별도 인코딩 없이 간단히 구현할 수 있습니다.)

 

두가지 방식을 안내드렸습니다.

제가 제안하는 방식은, 

업로드 방식을 변경할 수 있다면 2번항목을 참고해 업로드 방식을 변경하시길 권장드리며, 

서버의 인터페이스를 변경하지 못하는 경우 1번항목을 참고해 적용하시기 바랍니다.

험프리.김현수 Delphi/C++Builder