브라우저 및 node.js용 Axios 기반 선언적 HTTP 클라이언트.
선언적 HTTP 클라이언트에 익숙해진 Java 프로그래머가 작성했습니다.
목표는 모든 javascript/typescript 환경(실제로는 es6 환경)에서 간단하고 간결한 http 클라이언트를 제공하는 것입니다. ( 아직 아님! )
babel-plugin-transform-decorators-legacy
아직 매개변수 데코레이터를 지원하지 않으므로 RetrofitJ는 현재 TypeScript 환경에서만 작동합니다.
여기에 제안을 인용하세요:
필드, getter, setter 및 메서드 선언뿐만 아니라 전체 클래스를 꾸밀 수 있습니다. 인수와 함수 선언은 장식할 수 없습니다. -- 제안서 데코레이터에서
그리고 누군가가 이 요청을 제출했습니다 --> 매개변수 데코레이터?
이제 Retrofit처럼 덜 작성하고 더 많은 작업을 수행한 것처럼 http 세부 정보보다는 자체 http 인터페이스를 선언하는 데 집중하겠습니다.
마지막으로, Axios(javascript http 클라이언트)와 Retrofit(java http 클라이언트)을 작성하거나 업데이트해 주신 모든 분들께 감사드립니다. 그것들은 훌륭한 프로젝트이며 저에게 많은 것을 가르쳐줍니다.
이 프로그램은 Proxy
객체( es6 )와 Decorator
기능( 2 단계)에 의존하기 때문에 네이티브에서 es6을 지원하지 않는 IE8/9/10/11 및 기타 환경(보통 브라우저)에서는 작동하지 않습니다.
즉, RetrofitJ는 기본적으로 es6을 지원하는 모든 환경에서 작업할 수 있습니다.
Proxy
객체에 대해 지원되는 폴리필을 찾을 수 없습니다. 하지만 Decorator
의 경우 babel-plugin-transform-decorators-legacy
와 같은 바벨 지원을 통해 사용할 수 있습니다.
npm 사용:
npm install retrofitjs
// This is typescript demo, also javascript demo( it is if you remove all type define )
// In the first step, you must create your retrofit object.
let client = Retrofit . getBuilder ( )
. setConfig < RetrofitConfig > ( { /** config, you can use retrofit config or axios config */ } )
. addInterceptor ( /** your interceptor */ )
. setErrorHandler ( /** define your error handler */ )
. build ( ) ;
// This is the part of define any interface what you need.
@ HTTP ( "/testing" )
@ Headers ( [ "Cache-Control: no-store" ] )
class TestingClient {
@ GET ( "/demo1/:callByWho/:when" )
public demo1 ( @ Path ( "callByWho" ) name : string , @ Path ( "when" ) time : number ) : RetrofitPromise < string > & void {
}
@ POST ( "/demo2/:file" )
public demo2 ( @ Path ( "file" ) file : string , @ Header ( "cookie" ) val : string , @ Config localConfig : AxiosConfig ) : RetrofitPromise < string > & void {
}
}
// The final step, create your client.
export let testingClient = client . create ( TestingClient ) ;
// When you are calling this method, it is a http call actually.
testingClient . demo1 ( "itfinally" , Date . now ( ) ) . then ( response => {
// any code
} ) . catch ( reason => {
// any code
} ) ;
// And you can also get axios instance.
let axios : AxiosInstance = client . getEngine ( ) ;
Retrofit과 마찬가지로 RetrofitJ도 인터셉터 체인으로 구현됩니다. 모든 인터셉터는 order
필드별로 정렬하고 가장 큰 것부터 가장 작은 것 순으로 정렬합니다 .
// This is a interceptor interface
export interface Interceptor {
order : number ;
init ( config : RetrofitConfig ) : void ;
intercept ( chain : Chain ) : Promise < ResponseInterface < any > >
}
조심하세요 . RealCall
인터셉터는 마지막 인터셉터이므로 그래야 합니다.
기본 인터셉터이며 order
필드의 값은 0입니다. RetrofitJs는 이를 Axios 객체의 모든 http 요청을 보내는 데 사용했습니다.
충돌을 피하기 위해 256개 미만(256개 제외)의 주문 필드 수가 예약되어 있습니다.
이와 같이 자신만의 인터셉터를 쉽게 구현할 수 있습니다.
class MyInterceptor implement Interceptor {
public order : number = 256 ;
public init ( config : RetrofitConfig ) : void {
// Initializing your interceptor
}
public intercept ( chain : Chain ) : Promise < ResponseInterface < any > > {
// Your code
return chain . proceed ( chain . request ( ) ) ;
}
}
chain.proceed( chain.request() )
에 주목하세요. 이 코드는 요청을 계속할지 여부를 결정합니다.
chain.proceed
로 호출하면 현재 요청이 다음 인터셉터로 전송됩니다. 그렇지 않으면 나머지 인터셉터가 활성화되지 않습니다. 그리고 인터셉터 체인에서 오류가 발생하면 전체 프로세스가 종료되고 활성 오류 처리기가 됩니다.
실제로 플러그인은 인터셉터이므로 RetrofitJ용 플러그인을 직접 작성할 수 있습니다.
Retrofit.use( new MyInterceptor implements Interceptor {
public order: number = 20;
public init( config: RetrofitConfig ): void {
}
public intercept( chain: Chain ): Promise<ResponseInterface<any>> {
}
} );
인스턴스를 생성하면 Retrofit
에 모든 인터셉터가 추가됩니다.
플러그인의 주문 필드에는 제한이 없습니다. 실제로 플러그인과 기본 인터셉터용으로 예약된 숫자가 있습니다.
그리고 이것은 모두 기본 인터셉터입니다:
인터셉터 | 주문하다 |
---|---|
리얼콜 | 0 |
재시도 요청 인터셉터 | 1 |
로거인터셉터 | 5 |
이 인터셉터는 기본적으로 비활성화되어 있으며 멱등성 요청에 네트워크 이상이 있을 때 임의의 시간에 재시도합니다. 'GET' 요청을 보낼 때 연결 시간이 초과되는 것과 같습니다.
사용하려면 RetrofitConfig
에서 maxTry
및 timeout
설정해야 합니다.
RetrofitConfig
에서 설정할 수 있습니다.
{
"maxTry": "number",
"retryCondition": "RetryCondition"
}
RetryCondition
인터페이스이며 RetryCondition.handler
true를 반환하면 인터셉터는 요청을 다시 보내려고 시도합니다.
이 인터셉터는 기본적으로 비활성화되며 모든 요청/응답(또는 오류)을 기록하고 콘솔에 인쇄합니다.
RetrofitConfig
에서 설정할 수 있습니다.
{
"debug": "boolean"
}
요청을 쉽게 취소할 수 있습니다.
let tick = testingClient . demo1 ( ... args ) ;
// Careful the different between micro task and macro task
setTimeout ( ( ) => tick . cancel ( "your message" ) , 3000 ) ;
주의하세요. cancel
API는 RetrofitPromise
개체의 메서드이므로 다른 Promise 개체로 호출할 수 없습니다. 다음은 예입니다.
// It is wrong.
tick . then ( ( ) => { ... you code } ) . cancel ( "message" ) ;
요청을 취소하면 RequestCancelException
이 발생하며 오류 처리기에서 처리하거나 무시할 수 있습니다.
모든 예외를 균일하게 처리하려면 ErrorHandler
구현하십시오.
class MyErrorHandler implement ErrorHandler {
public handler ( realReason : any , exception : Exception ) : void {
// your code
}
}
realReason
은 axios에서 제공하는 매개변수이고 exception
Exception
의 인스턴스이므로 모든 예외를 쉽게 균일하게 처리할 수 있습니다.
이것은 모두 예외입니다.
예외 | 설명 |
---|---|
요청취소예외 | 사용자 취소 |
ConnectException | ECONNREFUSED 신호가 활성화되었습니다. |
소켓예외 | ECONNRESET 신호 활성화됨 |
요청시간초과예외 | ECONNABORTED 또는 ETIMEDOUT 신호가 활성화되었습니다. |
IO예외 | 나머지 알 수 없는 상황 |
오류 핸들러는 모든 예외를 포착할 수 있지만 이것이 Promise.catch
활성화되지 않는다는 의미는 아닙니다. 실제로 예외가 발생했을 때 정상적인 프로세스를 종료하기 위한 이유 때문에 필요합니다.
class MyErrorHandler implement ErrorHandler {
public handler ( realReason : any , exception : Exception ) : void {
// Your code
}
}
testingClient . demo1 ( ... args ) . then ( response => {
// Normal business process
} ) . catch ( reason => {
// Active after error handler call
} ) ;
단일 메소드 기호에서는 단일 매개변수를 다중 데코레이터로 꾸밀 수 없습니다.
// It is wrong!
public demo1 < T > ( @ Field ( "key1" ) @ Header ( "header1" ) val1 : any ) : RetrofitPromise < T > & void {
}
https://127.0.0.1/demo?key1=val1&key2=val2
와 같은 URL 쿼리를 생성하려면 다음과 같이 하십시오.
public demo1 < T > ( @ Query ( "key1" ) val1 : any , @ QueryMap map1 : object ) : RetrofitPromise < T > & void {
}
@Query
쿼리 키-값 항목을 선언합니다.@QueryMap
쿼리 다중 키 값 항목을 선언합니다.양식을 쉽게 제출할 수 있습니다.
@ FormUrlEncoded
public demo1 < T > ( @ Field ( "key1" ) val1 : any , @ FieldMap map1 : object ) : RetrofitPromise < T > & void {
}
@Field
및 @FieldMap
@FormUrlEncoded
에 의해 메소드가 선언된 경우에만 유효합니다.
@FormUrlEncoded
이것이 양식임을 선언합니다.@Field
양식 키-값 항목을 선언합니다.@FieldMap
다중 키-값 항목 형식을 선언합니다. JSON Body로 요청하려면 @Body
사용하여 매개변수를 장식하세요.
public demo1 < T > ( @ Body myBody : object ) : RetrofitPromise < T > & void {
}
단일 요청에 하나의 본문이 있으므로 @Body
@FormUrlEncoded
또는 @MultiPart
와 함께 사용할 수 없습니다. 또한 @Body
동일한 메소드 기호에 둘 이상 사용할 수 없습니다.
// It is wrong!
public demo1 < T > ( @ Body myBody : object , @ Body otherBody : object ) : RetrofitPromise < T > & void {
}
위의 경우와 마찬가지로 myBody
매개변수는 무시됩니다.
구성을 재정의하려면 @Config
사용하여 매개변수를 장식하세요.
public demo1 < T > ( @ Config config : RetrofitRequest ) : RetrofitPromise < T > & void {
}
매개변수 구성에 포함된 필드에 따라 데코레이터 설정(전역 구성은 포함되지 않음)이 재정의됩니다.
동적 구성은 요청에만 유효하지만 인터셉터 구성에는 적용되지 않습니다. 인터셉터는 Retrofit.getBuilder().build()
호출할 때 초기화되고 한 번만 초기화되기 때문입니다.
다음과 같이 RetrofitJs를 사용하여 파일을 쉽게 업로드할 수 있습니다.
@ MultiPart
@ PUT ( "/upload" )
public upload ( @ Part ( "file" ) file : any , @ PartMap anything : any ) : RetrofitPromise < void > & void {
}
이것은 브라우저 방식입니다.
// document.getElementById( "file" ) is a input tag
client . upload ( document . getElementById ( "file" ) . files [ 0 ] ) ;
그리고 이것은 노드 방식입니다:
// create a file read stream as parameter, done.
client . upload ( fs . createReadStream ( "your file path" ) ) ;
양식 제출과 마찬가지로 @Part
및 @PartMap
도 @MultiPart
에 의해 메소드가 선언된 경우에만 유효합니다.
@MultiPart
이것이 양식임을 선언합니다.@Part
양식 키-값 항목을 선언합니다.@PartMap
다중 키-값 항목 형식을 선언합니다.또한 서버의 최대 파일 크기 설정에 주의해야 합니다. 파일 크기가 서버 제한보다 크면 항상 업로드가 실패합니다.
마지막으로 Buffer
객체를 매개변수로 사용하지 마십시오. 버퍼 객체를 사용하여 업로드를 시도했지만 버퍼 객체에는 데이터만 있고 파일 이름, 파일 형식과 같은 설명이 없기 때문에 모두 실패했습니다.
브라우저에서는 Ajax가 항상 문자열 데이터로 응답하기 때문에 Ajax로 파일을 다운로드할 수 있는 방법은 없지만 iframe 태그를 사용하여 브라우저 다운로드를 활성화할 수 있습니다.
다음과 같이 노드에서 파일을 다운로드할 수 있습니다.
@ ResponseBody ( ResponseType . STREAM )
public demo1 ( ) : RetrofitPromise < Stream > & void {
}
@ResponseBody
RetrofitJ에 어떤 유형이 반환되어야 하는지 알려줍니다.
다음은 모두 지원되는 응답 유형입니다.
유형 | 값 |
---|---|
물체 | ResponseType.JSON(기본값) |
끈 | ResponseType.DOCUMENT, ResponseType.TEXT |
개울 | 응답 유형.STREAM |
완충기 | ResponseType.ARRAY_BUFFER |
보시다시피 RetrofitJ는 플랫폼만 제공하며 모든 http 인터페이스는 직접 작성해야 합니다.
또한 공통 인터페이스를 작성하고 확장한 후 정보 수집기가 다음과 같이 작동할 수 있습니다.
간단히 말해서, 정보 우선순위 체인은 @Config > 메소드 > 이 클래스 > 슈퍼 클래스를 따릅니다.
MIT