عميل HTTP التعريفي المستند إلى Axios للمتصفح وnode.js.
كتبه مبرمج جافا اعتاد على عميل HTTP التعريفي.
الهدف هو توفير عميل http بسيط وموجز في جميع بيئات جافا سكريبت/تايبسكريبت (بيئة es6، في الواقع) ( ليس بعد! )
نظرًا لأن babel-plugin-transform-decorators-legacy
لا يدعم مُزخرف المعلمات حتى الآن، لذا فإن RetrofitJs يعمل فقط على بيئة TypeScript في الوقت الحالي.
اقتبس الاقتراح هنا:
يمكنك تزيين الفصل بأكمله، بالإضافة إلى إعلانات الحقول والحروف والمحددات والأساليب. لا يمكن تزيين الوسائط وإعلانات الوظائف. -- من مصممي الاقتراحات
وأيضًا قام شخص ما بطرح هذا الطلب --> Parameter Decorators؟
الآن، دعونا نركز على الإعلان عن واجهة http الخاصة بها بدلاً من تفاصيل http، تمامًا كما فعلت عملية التعديل التحديثي، اكتب أقل وافعل المزيد.
أخيرًا، شكرًا جزيلاً لجميع الأشخاص الذين كتبوا أو قاموا بتحديث Axios (عميل JavaScript http) وRetrofit (عميل Java http) كثيرًا، فهذه مشاريع رائعة، لقد علمتني الكثير.
لا يمكن لهذا البرنامج العمل على IE8/9/10/11 والبيئات الأخرى (المتصفح عادة) التي لا تدعم es6 في النسخة الأصلية، لأنها تعتمد على كائن Proxy
(es6) وميزة Decorator
(المرحلة 2).
بمعنى آخر، يمكن أن تعمل RetrofitJs على أي بيئة تدعم es6 باللغة الأصلية.
بخصوص كائن Proxy
، لا أستطيع العثور على أي polyFill مدعوم. لكن بالنسبة لـ Decorator
، يمكنك استخدامه من خلال شيء يدعمه babel مثل 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 ( ) ;
مثل التحديث التحديثي، يتم تنفيذ التحديث التحديثي Js أيضًا من خلال سلسلة الاعتراض. يتم فرز جميع المعترضات حسب حقل order
، والفرز من الأكبر إلى الأصغر .
// This is a interceptor interface
export interface Interceptor {
order : number ;
init ( config : RetrofitConfig ) : void ;
intercept ( chain : Chain ) : Promise < ResponseInterface < any > >
}
كن حذرًا، فإن معترض RealCall
هو المعترض الأخير، ويجب أن يكون كذلك.
وهو اعتراض افتراضي، قيمة حقل order
هي صفر. استخدمه RetrofitJs لإرسال جميع طلبات http بواسطة كائن Axios.
لتجنب التعارض، يتم حجز أرقام حقول الطلب الأقل من 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
، فسيتم نقل الطلب الحالي إلى المعترض التالي. وإلا فإن المعترض الباقي لن يكون نشطا. وسيتم إنهاء العملية برمتها ومعالج الأخطاء النشط في حالة حدوث أي خطأ من سلسلة الاعتراض.
في الواقع، المكونات الإضافية هي أدوات اعتراضية، ويمكنك كتابة المكونات الإضافية الخاصة بك لـ RetrofitJs.
Retrofit.use( new MyInterceptor implements Interceptor {
public order: number = 20;
public init( config: RetrofitConfig ): void {
}
public intercept( chain: Chain ): Promise<ResponseInterface<any>> {
}
} );
سيضيف جميع الاعتراضات إلى Retrofit
عند إنشاء مثيل.
لا يوجد حد لمجال طلب المكونات الإضافية. في الواقع، هناك أرقام محجوزة للمكونات الإضافية والمعترضات الافتراضية.
وهذا هو كل المعترض الافتراضي:
المعترض | طلب |
---|---|
RealCall | 0 |
RetryRequestInterceptor | 1 |
LoggerInterceptor | 5 |
يتم تعطيل هذا المعترض بشكل افتراضي، وسيعيد المحاولة في وقت عشوائي عندما يكون الطلب غير الفعال به حالة شاذة في الشبكة. مثل مهلة الاتصال عند إرسال طلب "GET".
إذا كنت تريد استخدامه، فيجب عليك تعيين maxTry
و timeout
في RetrofitConfig
.
يمكنك الإعداد في RetrofitConfig
:
{
"maxTry": "number",
"retryCondition": "RetryCondition"
}
RetryCondition
عبارة عن واجهة، وسيحاول المعترض إرسال الطلب مرة أخرى إذا كان RetryCondition.handler
صحيحًا.
يتم تعطيل هذا المعترض بشكل افتراضي، وسوف يسجل كل الطلب/الاستجابة (أو الخطأ) ويطبعه على وحدة التحكم.
يمكنك الإعداد في RetrofitConfig
:
{
"debug": "boolean"
}
يمكنك بسهولة إلغاء الطلب.
let tick = testingClient . demo1 ( ... args ) ;
// Careful the different between micro task and macro task
setTimeout ( ( ) => tick . cancel ( "your message" ) , 3000 ) ;
انتبه، cancel
واجهة برمجة التطبيقات هو أسلوب لكائن RetrofitPromise
، ولا يمكنك الاتصال باستخدام كائن وعد آخر، وهذا مثال:
// 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 |
RequestTimeoutException | تم تفعيل إشارة ECONNABORTED أو ETIMEDOUT |
IOEException | بقية الوضع غير معروف |
على الرغم من أن معالج الأخطاء يمكن أن يلتقط كافة الاستثناءات، إلا أن هذا لا يعني أن 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 {
}
إذا كنت تريد إنشاء استعلام URL مثل https://127.0.0.1/demo?key1=val1&key2=val2
، فما عليك سوى القيام بذلك على النحو التالي:
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
لتزيين المعلمة.
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
بإخبار RetrofitJs بالنوع الذي يجب إرجاعه.
هذا هو كل نوع الاستجابة المدعومة:
يكتب | قيمة |
---|---|
هدف | ResponseType.JSON (افتراضي) |
خيط | نوع الاستجابة.DOCUMENT، نوع الاستجابة.TEXT |
تدفق | نوع الاستجابة.STREAM |
المخزن المؤقت | نوع الاستجابة.ARRAY_BUFFER |
هذا هو الفصل الأخير، كما ترون، توفر RetrofitJs نظامًا أساسيًا فقط، ويجب كتابة واجهة http بالكامل بنفسك.
كما يمكنك كتابة واجهة مشتركة وتوسيعها ، ومن ثم يعمل جامع المعلومات على النحو التالي:
باختصار، تتبع سلسلة أولوية المعلومات ما يلي: @Config > Method > this class > super class
معهد ماساتشوستس للتكنولوجيا