如何在 odoo 14 中使用 json 类型的路由设置响应状态代码

How to set response status code in route with type json in odoo 14

我在 odoo 14 中创建了一个 Json 类型的路由。

@http.route('/test', auth='public', methods=['POST'], type="json", csrf=False)
def recieve_data(self, **kw):
       headers = request.httprequest.headers
       args = request.httprequest.args
       data = request.jsonrequest

所以当我收到使用这条路线的请求时,一切都很好,但假设我想 return 一个不同的状态代码,比如 401,我不能用类型为 json 的路线做到这一点. 我也试过下面的方法,但这个方法的问题是它停止了所有 odoo 未来的请求。

from odoo.http import request, Response
@http.route('/test', auth='public', methods=['POST'], type="json", csrf=False)
def recieve_data(self, **kw):
      headers = request.httprequest.headers
      args = request.httprequest.args 
      data = request.jsonrequest
      Response.status = "401 unauthorized"
      return {'error' : 'You are not allowed to access the resource'}

所以在上面的例子中,如果我将响应状态代码设置为 401 所有其他请求,即使它们是针对不同的路由,也将被停止并且其状态代码更改为 401 。 我在odoo14和odoo13都检查过这个问题。

您无法指定响应代码,因为您可以看到状态代码已硬编码在 http.py:

def _json_response(self, result=None, error=None):

   # ......
   # ......

    return Response(
        body, status=error and error.pop('http_status', 200) or 200,
        headers=[('Content-Type', mime), ('Content-Length', len(body))]
    )

如果结果不是错误,状态代码始终为 200。但是您可以直接更改方法的代码或使用猴子补丁 如果在结果中指定状态代码不是很重要,请不要这样做 ^^.

一个简单的猴子补丁将其放入您想要此行为的模块的 __init__.py 中。

from odoo.http import JsonRequest

class JsonRequestPatch(JsonRequest):

    def _json_response(self, result=None, error=None):
        response = {
            'jsonrpc': '2.0',
            'id': self.jsonrequest.get('id')
            }
        default_code = 200
        if error is not None:
            response['error'] = error
        if result is not None:
            response['result'] = result
            # you don't want to remove some key of another result by mistake
            if isinstance(response, dict)
                defautl_code = response.pop('very_very_rare_key_here', default_code)

        mime = 'application/json'
        body = json.dumps(response, default=date_utils.json_default)

        return Response(
            body, status=error and error.pop('http_status', defautl_code ) or defautl_code,
            headers=[('Content-Type', mime), ('Content-Length', len(body))]
        )
        
        
JsonRequest._json_response = JsonRequestPatch._json_response

并且在 JSON api 的结果中,您可以像这样更改状态代码

 def some_controler(self, **kwargs):
        result = ......
        result['very_very_rare_key_here'] = 401
        return result

猴子补丁的风险是你完全覆盖了方法,如果在新版本的 Odoo 中做了一些改变,你也必须在你的方法中做。 上面的代码来自 odoo 13.0 当我构建一个 restfull 模块来使用网站时,我做了很多这样的事情使用 axios 不允许在 GET 中发送正文要求。并且 odoo 期望参数在 json 请求的主体内。