জ্যাকস-আরএস - জেএসএন এবং এইচটিটিপি স্থিতি কোড একসাথে কীভাবে ফিরিয়ে আনব?


248

আমি একটি REST ওয়েব অ্যাপ (নেটবিয়ানস 6.9, জ্যাকস-আরএস, টপলিংক এসেন্সিয়ালস) লিখছি এবং জেএসএন এবং এইচটিটিপি স্থিতির কোডটি ফেরত দেওয়ার চেষ্টা করছি । আমার কাছে কোড প্রস্তুত এবং কার্যকরী রয়েছে যা ক্লায়েন্টের কাছ থেকে HTTP GET পদ্ধতি কল করার পরে JSON প্রদান করে। মূলত:

@Path("get/id")
@GET
@Produces("application/json")
public M_機械 getMachineToUpdate(@PathParam("id") String id) {

    // some code to return JSON ...

    return myJson;
}

কিন্তু আমি আরো JSON তথ্য সহ একটি HTTP স্থিতি কোড (500, 200, 204, ইত্যাদি) ফিরে যেতে চাই।

আমি ব্যবহার করার চেষ্টা করেছি HttpServletResponse:

response.sendError("error message", 500);

তবে এটি ব্রাউজারটিকে ভাবায় এটি "সত্য" 500 তাই আউটপুট ওয়েব পৃষ্ঠাটি নিয়মিত এইচটিটিপি 500 ত্রুটি পৃষ্ঠা ছিল।

আমি একটি HTTP স্থিতি কোডটি ফিরিয়ে দিতে চাই যাতে আমার ক্লায়েন্ট-পাশের জাভাস্ক্রিপ্ট তার উপর নির্ভর করে কিছু যুক্তি পরিচালনা করতে পারে (উদাহরণস্বরূপ, কোনও HTML পৃষ্ঠায় ত্রুটি কোড এবং বার্তা প্রদর্শন করা)। এটি কি সম্ভব নাকি এই জাতীয় জিনিসটির জন্য এইচটিটিপি স্থিতি কোডগুলি ব্যবহার করা উচিত নয়?


2
আপনি চান 500 (অবাস্তব? :)) এবং বাস্তব 500 এর মধ্যে পার্থক্য কী?
রেজার

@ রেজার এখানে আসল 500 এর অর্থ জেএসএন প্রতিক্রিয়ার পরিবর্তে একটি এইচটিএমএল ত্রুটি পৃষ্ঠা
নূপুর

ওয়েব ব্রাউজারটি JSON এর সাথে কাজ করার জন্য ডিজাইন করা হয়নি, তবে এইচটিএমএল পৃষ্ঠাগুলির সাহায্যে তৈরি করা হয়েছে, সুতরাং আপনি যদি 500 (এবং এমনকি কিছু বার্তা মূল অংশ) দিয়ে প্রতিক্রিয়া জানান তবে ব্রাউজার আপনাকে কেবল একটি ত্রুটি বার্তা প্রদর্শন করতে পারে (ব্রাউজার বাস্তবায়নের উপর নির্ভর করে), কারণ এটি কার্যকর একটি সাধারণ ব্যবহারকারী
রেজার

উত্তর:


346

এখানে একটি উদাহরণ:

@GET
@Path("retrieve/{uuid}")
public Response retrieveSomething(@PathParam("uuid") String uuid) {
    if(uuid == null || uuid.trim().length() == 0) {
        return Response.serverError().entity("UUID cannot be blank").build();
    }
    Entity entity = service.getById(uuid);
    if(entity == null) {
        return Response.status(Response.Status.NOT_FOUND).entity("Entity not found for UUID: " + uuid).build();
    }
    String json = //convert entity to json
    return Response.ok(json, MediaType.APPLICATION_JSON).build();
}

কটাক্ষপাত রেসপন্স বর্গ।

নোট করুন যে আপনার সর্বদা একটি সামগ্রীর ধরণ নির্দিষ্ট করা উচিত, বিশেষত যদি আপনি একাধিক সামগ্রীর প্রকারগুলি পার করছেন তবে প্রতিটি বার্তাটি যদি JSON হিসাবে উপস্থাপন করা হয় তবে আপনি কেবল পদ্ধতিটি টিকিয়ে দিতে পারেন @Produces("application/json")


12
এটি কাজ করে, তবে প্রতিক্রিয়া রিটার্ন মান সম্পর্কে যা আমি পছন্দ করি না তা হ'ল আমার মতে এটি আপনার কোডকে দূষিত করে, বিশেষত যে কোনও ক্লায়েন্ট এটি ব্যবহার করার চেষ্টা করছে to যদি আপনি কোনও তৃতীয় পক্ষের প্রতিক্রিয়া ফেরত কোনও ইন্টারফেস সরবরাহ করেন তবে আপনি জানেন না আপনি কী ধরণের প্রকৃতপক্ষে ফিরে আসছেন। স্প্রিং এটি আরো একটি টীকা সঙ্গে পরিষ্কার, খুব দরকারী যদি আপনি সবসময় একটি স্থিতি কোড ফেরত তোলে (অর্থাত HTTP- র 204)
গাইডো

19
এই শ্রেণীর জেনেরিক (প্রতিক্রিয়া <টি>) তৈরি করা উভয় বিকল্পের সুবিধা পেতে জ্যাক্স-আরএসের আকর্ষণীয় উন্নতি হবে।
গুইডো

41
সত্তাকে কোনওভাবে জসনে রূপান্তর করার দরকার নেই। আপনি return Response.status(Response.Status.Forbidden).entity(myPOJO).build();যেমন চান তেমন কাজ করতে পারেন return myPOJO;তবে এইচটিটিপি-স্থিতি কোডের অতিরিক্ত সেটিং সহ।
kratenko

1
আমি মনে করি ব্যবসায়ের যুক্তিটিকে পৃথক পরিষেবা শ্রেণিতে আলাদা করা ভাল কাজ করে। শেষের অবস্থানটি প্রতিক্রিয়াটিকে রিটার্নের ধরণ হিসাবে ব্যবহার করে এবং এর পদ্ধতিগুলি কেবলমাত্র পরিষেবা পদ্ধতির প্লাস এবং প্যারাম টিকাতে কল হয়। এটি ইউআরএল / সামগ্রীর ধরণের ম্যাপিং থেকে পরিষ্কারভাবে যুক্তিটিকে পৃথক করে (যেখানে কথা বলতে রাবার রাস্তায় আঘাত করে)।
স্টিজন ডি উইট

আসলে, কেউ কেবল প্রতিক্রিয়াতে মোড়ানো না হয়ে অবজেক্টটি ফিরিয়ে দিতে পারে।
এসএস করুন

191

একটি REST ওয়েব পরিষেবাদিতে HTTP স্থিতি কোড সেট করার জন্য বেশ কয়েকটি ব্যবহারের কেস রয়েছে এবং বিদ্যমান উত্তরগুলিতে কমপক্ষে একটি পর্যাপ্তভাবে ডকুমেন্টেড ছিল না (যেমন আপনি যখন জ্যাকএক্সবি ব্যবহার করে অটো-ম্যাজিকাল জেএসএন / এক্সএমএল সিরিয়ালাইজেশন ব্যবহার করছেন, এবং আপনি কোনও ফিরিয়ে দিতে চান সিরিয়ালাইজড করতে বস্তু, তবে একটি ডিফল্ট 200 এর চেয়ে পৃথক একটি স্ট্যাটাস কোড)।

সুতরাং আমাকে চেষ্টা করুন এবং প্রতিটি ব্যবহারের জন্য বিভিন্ন ক্ষেত্রে এবং সমাধানগুলি গণনা করুন:

1. ত্রুটি কোড (500, 404, ...)

আপনি 200 OKযখন কোনও ত্রুটি দেখা দেয় তার চেয়ে আলাদা যখন আপনি কোনও স্ট্যাটাস কোড ফিরিয়ে দিতে চান তখন সর্বাধিক সাধারণ ব্যবহারের ক্ষেত্রে ।

উদাহরণ স্বরূপ:

  • একটি সত্তার অনুরোধ করা হয়েছে তবে এটি বিদ্যমান নেই (404)
  • অনুরোধ শব্দার্থগতভাবে ভুল (400)
  • ব্যবহারকারী অনুমোদিত নয় (401)
  • ডাটাবেস সংযোগে সমস্যা আছে (500)
  • ইত্যাদি ..

ক) একটি ব্যতিক্রম নিক্ষেপ

সেক্ষেত্রে, আমি মনে করি যে সমস্যাটি হ্যান্ডেল করার সর্বোত্তম উপায়টি একটি ব্যতিক্রম ছোঁড়া। এই ব্যতিক্রমটি একটি দ্বারা পরিচালিত হবে ExceptionMapper, যা উপযুক্ত ত্রুটি কোডের সাথে ব্যতিক্রমটিকে প্রতিক্রিয়াতে অনুবাদ করবে।

আপনি ExceptionMapperজার্সির সাথে পূর্ব-কনফিগার হওয়া ডিফল্টটি ব্যবহার করতে পারেন (এবং আমার ধারণা অন্যান্য বাস্তবায়নের সাথে এটি একই রকম) এবং বিদ্যমান সাব-ক্লাসগুলির যে কোনও একটি নিক্ষেপ করতে পারেন javax.ws.rs.WebApplicationException। এগুলি প্রাক-সংজ্ঞায়িত ব্যতিক্রম ধরন যা বিভিন্ন ত্রুটি কোডগুলিতে প্রাক ম্যাপ করা হয়, উদাহরণস্বরূপ:

  • BadRequestException (400)
  • অভ্যন্তরীণ সার্ভারআররএক্সপেশন (500)
  • নটফাউন্ডএক্সেপশন (404)

ইত্যাদি আপনি এখানে তালিকাটি খুঁজে পেতে পারেন: এপিআই

বিকল্পভাবে, আপনি নিজের কাস্টম ব্যতিক্রম এবং ExceptionMapperক্লাসগুলি সংজ্ঞায়িত করতে পারেন এবং টীকাটির মাধ্যমে এই ম্যাপারগুলি জার্সিতে যুক্ত করতে পারেন @Provider( এই উদাহরণের উত্স ):

public class MyApplicationException extends Exception implements Serializable
{
    private static final long serialVersionUID = 1L;
    public MyApplicationException() {
        super();
    }
    public MyApplicationException(String msg)   {
        super(msg);
    }
    public MyApplicationException(String msg, Exception e)  {
        super(msg, e);
    }
}

প্রদানকারী :

    @Provider
    public class MyApplicationExceptionHandler implements ExceptionMapper<MyApplicationException> 
    {
        @Override
        public Response toResponse(MyApplicationException exception) 
        {
            return Response.status(Status.BAD_REQUEST).entity(exception.getMessage()).build();  
        }
    }

দ্রষ্টব্য: আপনি যে ব্যতিক্রমগুলি ব্যবহার করেন সেগুলির জন্য আপনি এক্সপশনম্যাপারগুলিও লিখতে পারেন।

খ) রেসপন্স বিল্ডার ব্যবহার করুন

স্থিতি কোড সেট করার আর একটি উপায় হ'ল Responseনির্ধারিত কোডের সাথে প্রতিক্রিয়া তৈরি করতে কোনও বিল্ডারকে ব্যবহার করা ।

সেক্ষেত্রে আপনার পদ্ধতির রিটার্নের ধরণ অবশ্যই হবে javax.ws.rs.core.Response। এটি অন্যান্য বিভিন্ন প্রতিক্রিয়া যেমন বর্ণনা করা হয়েছে যেমন 'হাইড্রুয়েসনেস' গৃহীত উত্তর এবং এর মতো দেখায়:

@GET
@Path("myresource({id}")
public Response retrieveSomething(@PathParam("id") String id) {
    ...
    Entity entity = service.getById(uuid);
    if(entity == null) {
        return Response.status(Response.Status.NOT_FOUND).entity("Resource not found for ID: " + uuid).build();
    }
    ...
}

2. সাফল্য, তবে 200 নয়

আপনি যখন রিটার্নের স্থিতি সেট করতে চান তখন অন্য একটি ঘটনাটি যখন অপারেশন সফল হয়েছিল তবে আপনি শরীরে ফিরে আসা সামগ্রীর পাশাপাশি 200 এর চেয়ে আলাদা সাফল্য কোডটি ফিরে আসতে চান।

ঘন ঘন ব্যবহারের ক্ষেত্রে হ'ল আপনি যখন একটি নতুন সত্তা তৈরি করেন ( POSTঅনুরোধ) এবং কোনও নতুন 201 Createdস্থিতি কোড সহ এই নতুন সত্তা বা সম্ভবত সত্তাটি সম্পর্কে তথ্য ফিরে আসতে চান ।

একটি পদ্ধতি হ'ল উপরে বর্ণিত ঠিক মত প্রতিক্রিয়া অবজেক্টটি ব্যবহার করা এবং অনুরোধের বডিটি নিজেই সেট করা। যাইহোক, এটি করে আপনি জ্যাকএক্সবি দ্বারা সরবরাহিত এক্সএমএল বা জেএসএন-এ স্বয়ংক্রিয় সিরিয়ালাইজেশন ব্যবহার করার ক্ষমতাটি looseিলা করে ফেলেন।

এটি সত্তা অবজেক্টটি ফেরত দেওয়ার আসল পদ্ধতি যা JAXB দ্বারা JSON এ সিরিয়ালাইজ করা হবে:

@Path("/")
@POST
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public User addUser(User user){
    User newuser = ... do something like DB insert ...
    return newuser;
}

এটি নতুন তৈরি করা ব্যবহারকারীর একটি JSON উপস্থাপনা ফিরিয়ে দেবে, তবে ফেরতের স্থিতি 201 হবে না 200 হবে।

এখন সমস্যাটি হ'ল আমি যদি Responseবিল্ডারটি রিটার্ন কোড সেট করতে ব্যবহার করতে চাই তবে আমাকে Responseআমার পদ্ধতিতে কোনও অবজেক্ট ফিরিয়ে দিতে হবে । কীভাবে এখনও Userঅবজেক্টটি সিরিয়ালায়িত করা যায়?

ক) সার্লেটের প্রতিক্রিয়াতে কোডটি সেট করুন

এটি সমাধানের জন্য একটি পদ্ধতি হ'ল সার্লেট রিকুয়েস্টের অনুরোধটি পাওয়া এবং প্রতিক্রিয়া কোডটি ম্যানুয়ালি নিজেই সেট করা, যেমন গ্যারেট উইলসনের উত্তরে প্রদর্শিত হয়েছিল:

@Path("/")
@POST
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public User addUser(User user, @Context final HttpServletResponse response){

    User newUser = ...

    //set HTTP code to "201 Created"
    response.setStatus(HttpServletResponse.SC_CREATED);
    try {
        response.flushBuffer();
    }catch(Exception e){}

    return newUser;
}

পদ্ধতিটি এখনও একটি সত্তা অবজেক্ট ফেরত দেয় এবং স্থিতি কোডটি 201 হয়।

দ্রষ্টব্য যে এটি কাজ করতে, আমাকে প্রতিক্রিয়াটি ফ্লাশ করতে হয়েছিল। এটি আমাদের সুন্দর JAX_RS রিসোর্সে নিম্ন-স্তরের সার্লেট এপিআই কোডের একটি অপ্রীতিকর পুনরুত্থান এবং আরও খারাপ এটি হ্যাডারগুলি এর পরেও সংশোধনযোগ্য হতে পারে কারণ তারা ইতিমধ্যে তারে প্রেরণ করা হয়েছিল।

খ) সত্তার সাথে প্রতিক্রিয়া অবজেক্টটি ব্যবহার করুন

সেক্ষেত্রে সর্বোত্তম সমাধানটি হ'ল রেসপন্স অবজেক্টটি ব্যবহার করা এবং সত্তাকে এই রেসপন্স অবজেক্টটিতে সিরিয়ালাইজ করাতে সেট করা। সেই ক্ষেত্রে পে-লোড সত্তার ধরণটি চিহ্নিত করতে রেসপন্স অবজেক্টটি জেনেরিক করে দেওয়া ভাল তবে এটি বর্তমানে তা নয়।

@Path("/")
@POST
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public Response addUser(User user){

    User newUser = ...

    return Response.created(hateoas.buildLinkUri(newUser, "entity")).entity(restResponse).build();
}

সেক্ষেত্রে, আমরা স্ট্যাটাস কোডটি 201 এ সেট করতে রেসপন্স বিল্ডার শ্রেণীর তৈরি পদ্ধতিটি ব্যবহার করি We সত্তা () পদ্ধতির মাধ্যমে আমরা সত্তা অবজেক্ট (ব্যবহারকারী )কে প্রতিক্রিয়াতে পাস করি।

ফলাফলটি হ'ল এইচটিটিপি কোডটি 401 যেমনটি আমরা চেয়েছিলাম, এবং প্রতিক্রিয়ার বডিটি হ'ল ঠিক আগের মতো JSON যা আমরা যখন ব্যবহারকারীর অবজেক্টটি ফিরিয়ে দিয়েছিলাম তার আগে had এটি একটি অবস্থান শিরোনাম যোগ করে।

রেসপন্স ক্লাসে বিভিন্ন স্ট্যাটাসের (স্ট্যাটি?) জন্য অনেকগুলি বিল্ডার পদ্ধতি রয়েছে যেমন:

রেসপন্স.এসেপ্টেড () রেসপন্স.ওক () রেসপন্স.নো কনটেন্ট () রেসপন্স.নোট অ্যাকসেপ্টেবল ()

এনবি: হিটটোয়াস অবজেক্টটি হেল্পার ক্লাস যা আমি বিকাশের জন্য ইউআরআই তৈরি করতে সহায়তা করে। আপনাকে এখানে আপনার নিজস্ব প্রক্রিয়াটি নিয়ে আসতে হবে;)

এটা সম্বন্ধে.

আমি আশা করি এই দীর্ঘ প্রতিক্রিয়া কারওর পক্ষে সহায়তা করবে :)


আমি আশ্চর্য হয়েছি যদি প্রতিক্রিয়াটির পরিবর্তে ডেটা অবজেক্টটি নিজেই ফেরত দেওয়ার কোনও পরিষ্কার উপায় থাকে। flushপ্রকৃতপক্ষে নোংরা।
অ্যালিকেলজিন-কিলাকা

1
আমার কেবলমাত্র একটি পোষ্যের উঁকিঝুঁকি: 401 এর অর্থ এই নয় যে ব্যবহারকারী অনুমোদিত নয়। এর অর্থ ক্লায়েন্ট অনুমোদিত নয়, কারণ আপনি কে তিনি তা জানেন না server যদি কোনও লগড / অন্যথায় স্বীকৃত ব্যবহারকারীকে একটি নির্দিষ্ট ক্রিয়া করার অনুমতি না দেওয়া হয় তবে সঠিক প্রতিক্রিয়া কোড 403 নিষিদ্ধ।
ডেমোনব্ল্যাক

69

হিসাবরক্ষার দ্বারা উত্তরটি কাজ করবে, তবে এটি জ্যাকসন + জ্যাকসবি-র মতো সরবরাহকারীকে স্বয়ংক্রিয়ভাবে আপনার ফিরে আসা অবজেক্টকে কিছু আউটপুট ফর্ম্যাট যেমন জেএসএন রূপান্তর করতে দেয় এমন পুরো পদ্ধতির পরিবর্তন করে। একটি অ্যাপাচি সিএক্সএফ পোস্ট দ্বারা অনুপ্রাণিত (যা কোনও সিএক্সএফ-নির্দিষ্ট শ্রেণীর ব্যবহার করে) আমি প্রতিক্রিয়া কোডটি সেট করার একটি উপায় খুঁজে পেয়েছি যা কোনও জ্যাক্স-আরএস প্রয়োগে কাজ করা উচিত: একটি এইচটিপিএস সার্লেটরেসপোনস প্রসঙ্গে ইনজেক্ট করুন এবং ম্যানুয়ালি প্রতিক্রিয়া কোডটি সেট করুন। উদাহরণস্বরূপ, CREATEDউপযুক্ত সময়ে প্রতিক্রিয়া কোডটি কীভাবে সেট করবেন তা এখানে ।

@Path("/foos/{fooId}")
@PUT
@Consumes("application/json")
@Produces("application/json")
public Foo setFoo(@PathParam("fooID") final String fooID, final Foo foo, @Context final HttpServletResponse response)
{
  //TODO store foo in persistent storage
  if(itemDidNotExistBefore) //return 201 only if new object; TODO app-specific logic
  {
    response.setStatus(Response.Status.CREATED.getStatusCode());
  }
  return foo;  //TODO get latest foo from storage if needed
}

উন্নতি: অন্য একটি সম্পর্কিত উত্তর সন্ধানের পরে , আমি শিখেছি যে কেউ HttpServletResponseএকজন সদস্য ভেরিয়েবল হিসাবে ইনজেক্ট করতে পারে এমনকি সিঙ্গলটন পরিষেবা শ্রেণির জন্যও (অন্ততপক্ষে RESTEasy এ) !! বাস্তবায়নের বিশদ সহ এপিআইকে দূষিত করার চেয়ে এটি অনেক ভাল পদ্ধতির। এটি দেখতে এটি দেখতে হবে:

@Context  //injected response proxy supporting multiple threads
private HttpServletResponse response;

@Path("/foos/{fooId}")
@PUT
@Consumes("application/json")
@Produces("application/json")
public Foo setFoo(@PathParam("fooID") final String fooID, final Foo foo)
{
  //TODO store foo in persistent storage
  if(itemDidNotExistBefore) //return 201 only if new object; TODO app-specific logic
  {
    response.setStatus(Response.Status.CREATED.getStatusCode());
  }
  return foo;  //TODO get latest foo from storage if needed
}

আপনি আসলে পদ্ধতির সাথে একত্রিত করতে পারেন: এর সাথে পদ্ধতিটি বর্ননা করুন, এবং @Producesচূড়ান্তভাবে মিডিয়া প্রকারটি নির্দিষ্ট করবেন না Response.okএবং অনুরোধের সাথে মিলে যাওয়ার জন্য আপনি যথাযথ মিডিয়া টাইপে জ্যাকএক্সবি-সিরিয়ালাইজড পেয়ে যাবেন। (আমি কেবলমাত্র একটি একক পদ্ধতিতে এটি চেষ্টা করেছি যা এক্সএমএল বা জেএসওএন ফিরে আসতে পারে: @Producesটীকাটি ব্যতীত পদ্ধতিটিতে নিজেই
দুটিরও

আপনি ঠিক গ্যারেট। আমার উদাহরণটি একটি সামগ্রীর ধরণের সরবরাহের জোরের চিত্রের চেয়ে বেশি চিত্র ছিল। আমাদের পন্থা অনুরূপ, কিন্তু একটি ব্যবহার করার ব্যাপারে MessageBodyWriterএবং Providerযদিও এটি আপনার উদাহরণ কিছু কোড অনুপস্থিত মনে হয়, অন্তর্নিহিত বিষয়বস্তু আপস জন্য করতে পারবেন। : এখানে আরেকটি উত্তর আমি প্রদান করা এই প্রকাশ করেন stackoverflow.com/questions/5161466/...
hisdrewness

8
আমি স্থিতি কোডটি ওভাররাইড করতে অক্ষম response.setStatus()। উদাহরণস্বরূপ 404 পাওয়া যায় না এমন প্রতিক্রিয়া প্রেরণের একমাত্র উপায় হ'ল প্রতিক্রিয়া স্থিতি কোড সেট করা response.setStatus(404)তারপরে আউটপুট স্ট্রিমটি বন্ধ করুন response.getOutputStream().close()যাতে জ্যাক্স-আরএস আমার স্থিতি পুনরায় সেট করতে না পারে।
রব জুরলিংক

2
আমি একটি 201 কোড সেট করতে এই পদ্ধতির ব্যবহার করতে সক্ষম হয়েছি, তবে response.flushBuffer()আমার প্রতিক্রিয়া কোডটিকে ওভাররেড করে ফ্রেমওয়ার্কটি এড়াতে একটি ট্রাই-ক্যাচ ব্লক যুক্ত করতে হয়েছিল। খুব পরিষ্কার নয়।
পিয়ের হেনরি

1
@ রবজুরলিংক, আপনি যদি বিশেষত কোনওটি ফেরত নিতে চান তবে 404 Not Foundকেবল এটি ব্যবহার করা সহজ throw new NotFoundException()
গ্যারেট উইলসন

34

আপনি যদি আপনার রিসোর্স স্তরটি Responseঅবজেক্টগুলি থেকে পরিষ্কার রাখতে চান তবে আমি আপনাকে ব্যবহার @NameBindingএবং প্রয়োগের জন্য আবদ্ধ করার পরামর্শ দিচ্ছি ContainerResponseFilter

এখানে টীকা দেওয়ার মাংস:

package my.webservice.annotations.status;

import javax.ws.rs.NameBinding;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@NameBinding
@Retention(RetentionPolicy.RUNTIME)
public @interface Status {
  int CREATED = 201;
  int value();
}

এই ফিল্টার এর মাংস:

package my.webservice.interceptors.status;

import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerResponseContext;
import javax.ws.rs.container.ContainerResponseFilter;
import javax.ws.rs.ext.Provider;
import java.io.IOException;

@Provider
public class StatusFilter implements ContainerResponseFilter {

  @Override
  public void filter(ContainerRequestContext containerRequestContext, ContainerResponseContext containerResponseContext) throws IOException {
    if (containerResponseContext.getStatus() == 200) {
      for (Annotation annotation : containerResponseContext.getEntityAnnotations()) {
        if(annotation instanceof Status){
          containerResponseContext.setStatus(((Status) annotation).value());
          break;
        }
      }
    }
  }
}

এবং তারপরে আপনার সংস্থার বাস্তবায়নটি কেবল সহজভাবে হয়ে যায়:

package my.webservice.resources;

import my.webservice.annotations.status.StatusCreated;
import javax.ws.rs.*;

@Path("/my-resource-path")
public class MyResource{
  @POST
  @Status(Status.CREATED)
  public boolean create(){
    return true;
  }
}

এপিআই পরিষ্কার রাখে, সুন্দর উত্তর দেয়। @ স্ট্যাটাস (কোড = 205) এর মতো আপনার টীকাটি প্যারামিট্রাইজ করা কি সম্ভব হবে এবং ইন্টারসেপ্টার কোডটি আপনার নির্দিষ্ট করে যা কিছু দিয়েছিলেন তা দিয়ে প্রতিস্থাপন করবেন? আমি মনে করি যে এটি যখনই আপনার প্রয়োজন হবে কোডগুলি ওভাররাইড করার জন্য মূলত আপনাকে একটি টিকা দেবে।
ব্যবহারকারী 2800708

@ ব্যবহারকারী ২৮০০70০৮, আমি ইতিমধ্যে আমার স্থানীয় কোডটির জন্য এটি করেছি, আপনার পরামর্শ অনুসারে উত্তরটি আপডেট করেছে।
এনটলক

সুন্দর ধন্যবাদ. এই এবং কয়েকটি কৌশল সহ আমি মূলত এখন আমার কোডে আরআরটি এপিআইগুলি পরিষ্কার করতে সক্ষম হয়েছি, যাতে এটি কোনও সহজ জাভা ইন্টারফেসের সাথে এতে আরআরএসটির উল্লেখ নেই; এটি কেবল অন্য আরএমআই প্রক্রিয়া।
ব্যবহারকারী 2800708

6
স্থিতি ফিল্টারটিতে টীকাগুলির জন্য লুপিংয়ের পরিবর্তে আপনি @ সরবরাহকারীর পাশাপাশি @ স্ট্যাটাসের সাথে ফিল্টারটি টিকে করতে পারেন। তারপরে ফিল্টারটি কেবলমাত্র সেই সংস্থানগুলিতে কল করা হবে যা @ স্থিতি দিয়ে টীকাযুক্ত। এটি হ'ল নেমবাইন্ডিং
ট্রেভেরিজম

1
ভাল কলআউট এর StatusFilterসাথে টীকা দেওয়ার মতো একটি দুর্দান্ত পার্শ্ব প্রতিক্রিয়া নেই @Status: আপনাকে এনটোটেশনের valueক্ষেত্রের জন্য একটি ডিফল্ট সরবরাহ করতে হবে , বা ক্লাসটি বর্নিত করার সময় একটিটিকে ঘোষণা করতে হবে (উদাঃ @Status(200):)। এটি অবশ্যই আদর্শ নয়।
ফিল

6

আপনি যদি ব্যতিক্রমের কারণে স্থিতি কোডটি পরিবর্তন করতে চান তবে JAX-RS 2.0 এর সাথে আপনি এই জাতীয় একটি এক্সপেশনম্যাপার বাস্তবায়ন করতে পারেন। এটি পুরো অ্যাপ্লিকেশনটির জন্য এই জাতীয় ব্যতিক্রম পরিচালনা করে।

@Provider
public class UnauthorizedExceptionMapper implements ExceptionMapper<EJBAccessException> {

    @Override
    public Response toResponse(EJBAccessException exception) {
        return Response.status(Response.Status.UNAUTHORIZED.getStatusCode()).build();
    }

}

6

যদি আপনার ডাব্লুএস-আরএসের একটি ত্রুটি বাড়ানো দরকার তবে কেবল ওয়েব অ্যাপ্লিকেশনএক্সসেপশনটি ব্যবহার করবেন না কেন?

@GET
@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
@Path("{id}")
public MyEntity getFoo(@PathParam("id") long id,  @QueryParam("lang")long idLanguage) {

if (idLanguage== 0){
    // No URL parameter idLanguage was sent
    ResponseBuilder builder = Response.status(Response.Status.BAD_REQUEST);
    builder.entity("Missing idLanguage parameter on request");
    Response response = builder.build();
    throw new WebApplicationException(response);
    }
... //other stuff to return my entity
return myEntity;
}

4
আমার মতে ওয়েব অ্যাপ্লিকেশনএক্সসেপ্টগুলি ক্লায়েন্টের পার্শ্ব ত্রুটির জন্য উপযুক্ত নয় কারণ তারা বড় স্ট্যাকের চিহ্ন ফেলে দেয়। ক্লায়েন্ট ত্রুটিগুলি সার্ভারের পাশের স্ট্যাকের চিহ্নগুলি ফেলে দেওয়া উচিত নয় এবং এর সাথে লগিংকে দূষিত করা উচিত।
রব জুউরলিংক

5

জ্যাক্স-আরএসের মানক / কাস্টম এইচটিটিপি কোডগুলির জন্য সমর্থন রয়েছে। রেসপন্সবিল্ডার এবং রেসপন্সস্ট্যাটাস দেখুন, উদাহরণস্বরূপ:

http://jackson.codehaus.org/javadoc/jax-rs/1.0/javax/ws/rs/core/Response.ResponseBuilder.html#status%28javax.ws.rs.core.Response.Status%29

মনে রাখবেন যে জেএসএন তথ্য সংস্থান / অ্যাপ্লিকেশন সম্পর্কিত ডেটা সম্পর্কে আরও বেশি। এইচটিটিপি কোডগুলি সিআরইউডি অপারেশনের স্থিতি সম্পর্কে অনুরোধ করা হচ্ছে। (কমপক্ষে এটি আরএসটি-ফুল সিস্টেমগুলিতে থাকার কথা)


লিঙ্কটি নষ্ট হয়েছে
উম্পা

5

আমি বারবার কোড সহ একটি জসন বার্তা তৈরি করা খুব দরকারী বলে খুঁজে পেয়েছি:

@POST
@Consumes("application/json")
@Produces("application/json")
public Response authUser(JsonObject authData) {
    String email = authData.getString("email");
    String password = authData.getString("password");
    JSONObject json = new JSONObject();
    if (email.equalsIgnoreCase(user.getEmail()) && password.equalsIgnoreCase(user.getPassword())) {
        json.put("status", "success");
        json.put("code", Response.Status.OK.getStatusCode());
        json.put("message", "User " + authData.getString("email") + " authenticated.");
        return Response.ok(json.toString()).build();
    } else {
        json.put("status", "error");
        json.put("code", Response.Status.NOT_FOUND.getStatusCode());
        json.put("message", "User " + authData.getString("email") + " not found.");
        return Response.status(Response.Status.NOT_FOUND).entity(json.toString()).build();
    }
}

4

দয়া করে এখানে উদাহরণটি দেখুন, এটি সমস্যাটি কীভাবে জার্সির সর্বশেষ (২.৩.১) সংস্করণে সমাধান করা হয়েছে তা সর্বোত্তমভাবে বর্ণনা করে।

https://jersey.java.net/documentation/latest/representations.html#d0e3586

এটিতে মূলত একটি কাস্টম ব্যতিক্রম সংজ্ঞা দেওয়া এবং রিটার্নের ধরণটিকে সত্তা হিসাবে রাখা অন্তর্ভুক্ত। যখন কোনও ত্রুটি হয়, ব্যতিক্রম নিক্ষেপ করা হয়, অন্যথায়, আপনি POJO ফিরিয়ে দেন।


আমি যুক্ত করতে চাই যে আগ্রহের উদাহরণ হ'ল তারা যেখানে তাদের নিজস্ব ব্যতিক্রম শ্রেণিটি সংজ্ঞায়িত করে এবং এতে একটি গঠন তৈরি Responseকরে। শুধু জন্য চেহারা CustomNotFoundExceptionবর্গ এবং হয়ত আপনার পোস্টে কপি।
জেবার্ট

আমি এই পদ্ধতির ত্রুটিগুলির জন্য ব্যবহার করি এবং আমি এটি পছন্দ করি। তবে এটি '201 তৈরি' এর মতো সাফল্যের কোডগুলিতে (২০০ এর পরে আলাদা) প্রযোজ্য নয়।
পিয়েরে হেনরি

3

আমি জ্যাকস-আরএস ব্যবহার করছি না, তবে যেখানে আমি ব্যবহার করব সেখানেও আমি একই জাতীয় দৃশ্য পেয়েছি:

response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());

এটি আমার জন্য স্প্রিং এমভিসি ব্যবহার করে তবে এটির জন্য একটি সহজ উপায় আছে!
ক্যাপস

1

এছাড়াও, লক্ষ্য করুন যে ডিফল্টরূপে জার্সি একটি HTTP কোড 400 বা তার বেশি ক্ষেত্রে ক্ষেত্রে প্রতিক্রিয়া বডিকে ওভাররাইড করবে।

প্রতিক্রিয়া সংস্থা হিসাবে আপনার নির্দিষ্ট সত্তাটি পেতে, আপনার ওয়েব.এক্সএমএল কনফিগারেশন ফাইলে আপনার জার্সিতে নিম্নলিখিত সূচনা-পরম যুক্ত করার চেষ্টা করুন:

    <init-param>
        <!-- used to overwrite default 4xx state pages -->
        <param-name>jersey.config.server.response.setStatusOverSendError</param-name>
        <param-value>true</param-value>
    </init-param>

0

নিম্নলিখিত কোডটি আমার পক্ষে কাজ করেছিল। টীকাযুক্ত সেটারের মাধ্যমে বার্তাসূত্রটি ইনজেকশন করা এবং আমার "অ্যাড" পদ্ধতিতে স্থিতি কোডটি সেট করা।

import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.Response;

import org.apache.cxf.jaxrs.ext.MessageContext;

public class FlightReservationService {

    MessageContext messageContext;

    private final Map<Long, FlightReservation> flightReservations = new HashMap<>();

    @Context
    public void setMessageContext(MessageContext messageContext) {
        this.messageContext = messageContext;
    }

    @Override
    public Collection<FlightReservation> list() {
        return flightReservations.values();
    }

    @Path("/{id}")
    @Produces("application/json")
    @GET
    public FlightReservation get(Long id) {
        return flightReservations.get(id);
    }

    @Path("/")
    @Consumes("application/json")
    @Produces("application/json")
    @POST
    public void add(FlightReservation booking) {
        messageContext.getHttpServletResponse().setStatus(Response.Status.CREATED.getStatusCode());
        flightReservations.put(booking.getId(), booking);
    }

    @Path("/")
    @Consumes("application/json")
    @PUT
    public void update(FlightReservation booking) {
        flightReservations.remove(booking.getId());
        flightReservations.put(booking.getId(), booking);
    }

    @Path("/{id}")
    @DELETE
    public void remove(Long id) {
        flightReservations.remove(id);
    }
}

0

উপর সম্প্রসারিত উত্তর এর Nthalk সঙ্গে Microprofile OpenAPI আপনি আপনার ডকুমেন্টেশন ব্যবহার করে আগমন কোড সারিবদ্ধ করতে @APIResponse টীকা।

এটি কোনও JAX-RS পদ্ধতিতে ট্যাগ করার অনুমতি দেয়

@GET
@APIResponse(responseCode = "204")
public Resource getResource(ResourceRequest request) 

আপনি এই ধারক টীকাটি একটি কনটেইনার রিস্পনস ফিল্টার দিয়ে পার্স করতে পারেন

@Provider
public class StatusFilter implements ContainerResponseFilter {

    @Override
    public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext) {
        if (responseContext.getStatus() == 200) {
            for (final var annotation : responseContext.getEntityAnnotations()) {
                if (annotation instanceof APIResponse response) {
                    final var rawCode = response.responseCode();
                    final var statusCode = Integer.parseInt(rawCode);

                    responseContext.setStatus(statusCode);
                }
            }
        }
    }

}

আপনি যখন আপনার পদ্ধতির মতো একাধিক টিকা রচনা করেন তখন একটি সতর্কতামূলক ঘটনা ঘটে

@APIResponse(responseCode = "201", description = "first use case")
@APIResponse(responseCode = "204", description = "because you can")
public Resource getResource(ResourceRequest request) 

-1

আমি বার্তা বডি রিডার এবং লেখকদের সাথে জার্সি 2.0 ব্যবহার করছি। আমার একটি নির্দিষ্ট সত্তা হিসাবে আমার পদ্ধতির রিটার্নের ধরণ ছিল যা বার্তা বডি রাইটার বাস্তবায়নেও ব্যবহৃত হয়েছিল এবং আমি একই স্কোজিস্টডিটিটিও ফিরে আসছিলাম। @ জিইটি @ কনসুমস ({"অ্যাপ্লিকেশন / এক্সএমএল", "অ্যাপ্লিকেশন / জেসন"}) @ প্রোডাক্টস ({"অ্যাপ্লিকেশন / এক্সএমএল", "অ্যাপ্লিকেশন / জেসন"}) @ পাথ ("/ skuResync")

public SkuResultListDTO getSkuData()
    ....
return SkuResultListDTO;

আমি পরিবর্তিত সমস্ত এটি ছিল, আমি লেখক বাস্তবায়ন একা ছেড়েছি এবং এটি এখনও কাজ করে।

public Response getSkuData()
...
return Response.status(Response.Status.FORBIDDEN).entity(dfCoreResultListDTO).build();
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.