Как вернуть ошибку кода состояния из службы REST при использовании обработчика OnError?

Я пытаюсь настроить некоторые веб-службы REST с помощью ColdFusion 10, и если у меня есть обработчик onError в Application.cfc, код состояния ошибки не возвращается обратно потребителю.

Рассмотрим это Application.cfc

<cfcomponent displayname="ApplicationCFC" output="true" >
    <cfscript>
        this.name = "learnWith";
        this.applicationTimeout = createTimeSpan(1,1,0,0);
        this.sessionManagement = "false";
        this.restsettings.autoregister = true;
        this.restsettings.skipCFCWithError = true;
    </cfscript>

    <cffunction name="onApplicationStart" returntype="boolean" output="true">
        <cfset RestInitApplication(expandPath('/myDir'),"lw")>
        <cfreturn true>
    </cffunction>
</cfcomponent>

Теперь рассмотрим сервис, например:

<cfcomponent rest="true" restpath="/user">
    <cffunction name="authenticate" access="remote" restpath="/login" returntype="String" httpmethod="POST"
            consumes="application/json" produces="application/json">
        <cfset requestData = getHTTPRequestData()>
        <cfset userInfo = deserializeJSON(ToString(requestData.content)) />

        <!--- cfquery to load user data ---->

        <cfif local.dataQuery.recordcount EQ 1>
            <cfset local.userVO = createObject()> <!--- create and populate userVo here --->
            <cfreturn SerializeJSON(local.userVO)>
        <cfelse>
            <!--- user not found, throw 401 error --->
            <cfthrow type="RestError" errorcode="401"  />
        </cfif>
    </cffunction>
</cfcomponent>

Этот код отлично работает от Postman. Если я передам надлежащие учетные данные

{
    "userName": "user",
    "password": "hashedPassword
}

Я возвращаю пользовательский объект, как и ожидалось, с ответом 200.

Правильный вход с учетными данными

Если я передам поддельные или недействительные учетные данные:

{
    "userName": "fakeuser",
    "password": "fakePassword
}

Я получаю обратно ошибку 401:

Ошибка аутентификации

Это идеально. Однако я хочу использовать глобальный обработчик ошибок для CFC как для кода, не основанного на службе REST, так и для регистрации возможных ошибок службы REST. Если я добавлю это в Application.cfc

    <cffunction name="onError" returnType="void" output="true">
        <cfargument name="exception" required="true">
        <cfargument name="eventname" type="string" required="true">
        <!--- error logging here --->
        <cfthrow type="RestError" errorcode="401" />
        <!--- or 
            <cfthrow type="#arguments.exception.Cause.Cause.type#" 
                     errorcode="#arguments.exception.Cause.Cause.code#">--->

    </cffunction>

ColdFusion возвращает сообщение об ошибке 500 Internal Server.

500 Внутренняя ошибка сервера

Я экспериментировал с cfheader как в методе CFC, так и в обработчике onError:

<cfheader statusCode = "401" statusText = "RestError">

Он вернет 200 без тела вместо статуса 401:

Ошибка 200

Я пробовал различные итерации этого, но я в недоумении. Могу ли я использовать коды состояния из службы отдыха ColdFusion при наличии обработчика onError? И если да, то как?


person JeffryHouser    schedule 17.05.2021    source источник
comment
Я думаю, проблема может заключаться в том, что у вас есть этот код в вашем onError методе <cfthrow type="RestError" errorcode="401" />. При вызове метода onError уже произошла ошибка, и вы выдаете другую ошибку из обработчика ошибок. Я думаю, вы должны иметь возможность использовать <cfheader statuscode="401" statustext="Unauthorized" /> в методе onError для возврата определенных кодов состояния HTTP. Но не используйте cfthrow. По крайней мере, не в самом методе onError.   -  person Miguel-F    schedule 17.05.2021
comment
@Miguel-F Если я удалю cfthrow и получу метод onError без кода, я все равно не получу 401 обратно на сервер. Похоже, что решение использует restSetResponse() для отправки ответа без использования cfthrow или возврата элемента. Я опубликую что-нибудь более подробное.   -  person JeffryHouser    schedule 18.05.2021
comment
Ответ, который вы опубликовали, является лучшим решением, чем выдача ошибки, но, чтобы быть ясным, я не хотел, чтобы вы пробовали метод onError без кода. Вам по-прежнему нужен код <cfheader ...>, о котором я упоминал. В любом случае, рад, что у вас все заработало.   -  person Miguel-F    schedule 18.05.2021
comment
@ Miguel-F Заголовок cfheader не влияет на использование REST API CF, независимо от того, находится ли он в методе onError или в методе CFC. Я указал на это в своем первоначальном вопросе.   -  person JeffryHouser    schedule 19.05.2021


Ответы (1)


Я смог сделать то, что я хочу. Вместо использования cfthrow для создания ошибки я могу создать нужный мне ответ с помощью restSetResponse.

Внутри cffunction сначала убедитесь, что тип возвращаемого значения установлен как void.

Затем вместо возврата объекта или использования cfthrow вы хотите создать объект ответа вручную и отправить его обратно с помощью restSetResponse.

Это решило мою проблему:

<cfcomponent rest="true" restpath="/user">
    <cffunction name="authenticate" access="remote" restpath="/login" returntype="void" httpmethod="POST"
            consumes="application/json" produces="application/json">
        <cfset requestData = getHTTPRequestData()>
        <cfset userInfo = deserializeJSON(ToString(requestData.content)) />

        <!--- cfquery to load user data ---->

        <cfset local.result = structNew()/>

        <cfif local.dataQuery.recordcount EQ 1>
            <cfset local.userVO = createObject()> <!--- create and populate userVo here --->

            <cfset local.result.status = 200 />
            <cfset local.result.content = SerializeJSON(local.userVO) />
        <cfelse>
            <cfset local.result.status = 401 />
            <cfset local.result.content = SerializeJSON({message: 'User Not Authorized'}) />
        </cfif>

        <cfset restSetResponse(local.result) />
    </cffunction>
</cfcomponent>

Как только я это сделал, я смог контролировать ответ моему потребителю, не вызывая метод onError в файле Application.cfc.

person JeffryHouser    schedule 18.05.2021