سؤال

أنا أتعلم Jax-Rs (AKA، JSR-311) باستخدام جيرسي. لقد أنشأت نجاحي مورد جذر وألعب مع المعلمات:

@Path("/hello")
public class HelloWorldResource {

    @GET
    @Produces("text/html")
    public String get(
        @QueryParam("name") String name,
        @QueryParam("birthDate") Date birthDate) {

         // Return a greeting with the name and age
    }
}

يعمل هذا رائعا، وتعامل مع أي تنسيق في اللغة الحالية التي يفهمها منشئ التاريخ (سلسلة) التاريخ (مثل Yyyy / MM / DD و MM / DD / YYYY). ولكن إذا قمت بتوفير قيمة غير صالحة أو غير مفهومة، أحصل على استجابة 404.

علي سبيل المثال:

GET /hello?name=Mark&birthDate=X

404 Not Found

كيف يمكنني تخصيص هذا السلوك؟ ربما رمز استجابة مختلف (ربما "400 طلب سيء")؟ ماذا عن تسجيل خطأ؟ ربما أضف وصفا للمشكلة ("تنسيق التاريخ السيئ") في رأس مخصص للمساعدة في استكشاف الأخطاء وإصلاحها؟ أو إرجاع استجابة خطأ كاملة مع التفاصيل، جنبا إلى جنب مع رمز حالة 5xx؟

هل كانت مفيدة؟

المحلول

هناك العديد من الأساليب لتخصيص سلوك معالجة الأخطاء مع JAX-RS. هنا ثلاثة من الطرق أسهل.

النهج الأول هو إنشاء فئة استثناء يمتد WebApplicationException.

مثال:

public class NotAuthorizedException extends WebApplicationException {
     public NotAuthorizedException(String message) {
         super(Response.status(Response.Status.UNAUTHORIZED)
             .entity(message).type(MediaType.TEXT_PLAIN).build());
     }
}

ورمي هذا الخلق حديثا استثناء ببساطة:

@Path("accounts/{accountId}/")
    public Item getItem(@PathParam("accountId") String accountId) {
       // An unauthorized user tries to enter
       throw new NotAuthorizedException("You Don't Have Permission");
}

لاحظ، لا تحتاج إلى إعلان الاستثناء في جملة رمزية لأن WebApplicationException هو استثناء وقت التشغيل. سيعود هذا استجابة 401 للعميل.

النهج الثاني والأسهل هو بناء مثيل WebApplicationException مباشرة في التعليمات البرمجية الخاصة بك. يعمل هذا النهج طالما لم يكن لديك لتنفيذ استثناءات التطبيق الخاصة بك.

مثال:

@Path("accounts/{accountId}/")
public Item getItem(@PathParam("accountId") String accountId) {
   // An unauthorized user tries to enter
   throw new WebApplicationException(Response.Status.UNAUTHORIZED);
}

يعيد هذا الرمز أيضا 401 إلى العميل.

بالطبع، هذا مجرد مثال بسيط. يمكنك الاستمتاع باستثناء أكثر تعقيدا إذا لزم الأمر، ويمكنك إنشاء رمز استجابة HTTP الذي تحتاج إليه.

يتمثل أحد النهج الآخر في التفاف استثناءا موجودا، وربما enjobsnotfoundException مع فئة مجمع صغيرة تنفذ واجهة الاستثناء المشروح مع شرحprovider. يخبر هذا وقت تشغيل JAX-RS، أنه إذا تم رفع الاستثناء المغطى، إرجاع رمز الاستجابة المحدد في الاستثناء.

نصائح أخرى

@Provider
public class BadURIExceptionMapper implements ExceptionMapper<NotFoundException> {

public Response toResponse(NotFoundException exception){

    return Response.status(Response.Status.NOT_FOUND).
    entity(new ErrorResponse(exception.getClass().toString(),
                exception.getMessage()) ).
    build();
}
}

إنشاء الطبقة فوق. سيؤدي ذلك إلى التعامل مع 404 (NotfoundException) وهنا في طريقة Toresponse، يمكنك تقديم استجابة مخصصة. وبالمثل، هناك paramexception وما إلى ذلك. والتي تحتاج إلى تعيين لتقديم ردود مخصصة.

جيرسي يلقي كوم.سكون. jersey.api.piaramexception عندما يفشل في unmarshall المعلمات لذلك حل واحد هو إنشاء استثناء يتعامل مع هذه الأنواع من الاستثناءات:

@Provider
public class ParamExceptionMapper implements ExceptionMapper<ParamException> {
    @Override
    public Response toResponse(ParamException exception) {
        return Response.status(Status.BAD_REQUEST).entity(exception.getParameterName() + " incorrect type").build();
    }
}

يمكنك أيضا كتابة فئة قابلة لإعادة الاستخدام لمتغيرات QueryParam

public class DateParam {
  private SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");

  private Calendar date;

  public DateParam(String in) throws WebApplicationException {
    try {
      date = Calendar.getInstance();
      date.setTime(format.parse(in));
    }
    catch (ParseException exception) {
      throw new WebApplicationException(400);
    }
  }
  public Calendar getDate() {
    return date;
  }
  public String format() {
    return format.format(value.getTime());
  }
}

ثم استخدمه مثل هذا:

private @QueryParam("from") DateParam startDateParam;
private @QueryParam("to") DateParam endDateParam;
// ...
startDateParam.getDate();

على الرغم من أن معالجة الأخطاء تافهة في هذه الحالة (قم بإلقاء استجابة 400)، فإن استخدام هذه الفئة يتيح لك التعامل مع المعلمة العوم بشكل عام والتي قد تتضمن التسجيل إلخ.

حل واحد واضح: تأخذ في سلسلة، وتحويل لتاريخ نفسك. بهذه الطريقة يمكنك تحديد التنسيق الذي تريده، والاستثناءات وإما إعادة رمي أو تخصيص خطأ يتم إرسالها. لتحليل، يجب أن تعمل SimpleedateFormat بشكل جيد.

أنا متأكد من أن هناك طرق لربط معالجات لأنواع البيانات أيضا، ولكن ربما يكون القليل من التعليمات البرمجية البسيطة كل ما تحتاجه في هذه الحالة.

أنا أيضا ستيكسمان من المحتمل أن تنفذ هذا QueryParam كسلسلة، ثم التعامل مع التحويل، وإعادة النظر حسب الضرورة.

إذا كان السلوك المحدد هو السلوك المرغوب والموقع، فسيستخدم ما يلي لإرجاع خطأ في طلب 400 سيئ:

throw new WebApplicationException(Response.Status.BAD_REQUEST);

رؤية جافادوك ل javax.ws.rs.core.response.status. لمزيد من الخيارات.

تقول وثائق queryparam

"يجب أن يكون نوع T من المعلمة المشروح أو الحقل أو الخاصية إما:

1) كن نوع بدائي
2) لديك منشئ يقبل حجة سلسلة واحدة
3) هل لديك طريقة ثابتة تسمى ValueOf أو FromString تقبل حجة سلسلة واحدة (انظر، على سبيل المثال، InteGer.Valueof (سلسلة))
4) هل لديك تطبيق مسجل ل JAVAX.WS.rs.ext.paramconverterprovider Jax-RS تمديد SPI يعيد JAVAX.WS.RS.EXT.Paramconverter قادر على تحويل "من سلسلة" للنوع.
5) كن قائمة أو مجموعة أو فرزها، حيث ترضي T 2 أو 3 أو 4 أعلاه. المجموعة الناتجة هي للقراءة فقط. "

إذا كنت ترغب في التحكم في الاستجابة التي يذهب إليها المستخدم عند تحويل المعلمة الاستعلام في نموذج السلسلة إلى النوع T، يمكنك رمي WebApplicationException. يأتي DropWizard مع يلي * فصول برمجية يمكنك استخدام احتياجاتك.

BooleanAnParam، Datetimeparam، Intparam، LongParam، LocalDateParam، NonemptystringParam، Uuidparam. يرى https://github.com/dropwizard/dropwizard/tree/master/dropwizard-jersey/src/main/java/io/dropwizard/jersey/params.

إذا كنت بحاجة إلى DateTime JODA، ما عليك سوى استخدام DropWizard DateTimeparam..

إذا كانت القائمة أعلاه لا تناسب احتياجاتك، فحدد بنفسك عن طريق تمديد التبريد. تجاوز طريقة التحليل. إذا كنت بحاجة إلى السيطرة على جسم استجابة الخطأ، فقم بتجاوز طريقة الخطأ.

مقال جيد من Coda Hale على هذا هو في http://codahale.com/what-makes-jersey-interesting-parameter-classes/

import io.dropwizard.jersey.params.AbstractParam;

import java.util.Date;

import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;

public class DateParam extends AbstractParam<Date> {

    public DateParam(String input) {
        super(input);
    }

    @Override
    protected Date parse(String input) throws Exception {
        return new Date(input);
    }

    @Override
    protected Response error(String input, Exception e) {
        // customize response body if you like here by specifying entity
        return Response.status(Status.BAD_REQUEST).build();
    }
}

تاريخ (سلسلة سلسلة) تم إهمال منشئ. أود استخدام فئات Java 8 Date إذا كنت في Java 8. وإلا ينصح وقت تاريخ JODA.

هذا هو السلوك الصحيح في الواقع. سيحاول جيرسي العثور على معالج لإدخالك وستحاول إنشاء كائن من المدخلات المقدمة. في هذه الحالة، سيحاول إنشاء كائن تاريخ جديد بقيمة X المقدمة إلى المنشئ. منذ هذا هو تاريخ غير صالح، سيعود المؤتمر جيرسي 404.

ما يمكنك فعله هو إعادة كتابة وتاريخ الميلاد كسلسلة، ثم حاول التحليل وإذا لم تحصل على ما تريد، فأنت حر في إلقاء أي استثناء تريده من خلال أي من آليات تعيين الاستثناءات (هناك عدة ).

تماما كملحق ل Steven Lavine الإجابة في حال كنت ترغب في فتح نافذة تسجيل الدخول المتصفح. لقد وجدت صعوبة في إعادة الاستجابة بشكل صحيح (مصادقة HTTP MDN.) من المرشح في حالة عدم مصادقة المستخدم بعد

ساعدني هذا في بناء الاستجابة لإجبار تسجيل دخول المتصفح، لاحظ التعديل الإضافي للرؤوس. سيقوم هذا بتعيين رمز الحالة إلى 401 وتعيين الرأس الذي يؤدي إلى فتح المستعرض مربع حوار اسم المستخدم / كلمة المرور.

// The extended Exception class
public class NotLoggedInException extends WebApplicationException {
  public NotLoggedInException(String message) {
    super(Response.status(Response.Status.UNAUTHORIZED)
      .entity(message)
      .type(MediaType.TEXT_PLAIN)
      .header("WWW-Authenticate", "Basic realm=SecuredApp").build()); 
  }
}

// Usage in the Filter
if(headers.get("Authorization") == null) { throw new NotLoggedInException("Not logged in"); }
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top