簡體   English   中英

在GAE python上為webapp2處理程序定義請求和響應對象

[英]Defining request and response objects for webapp2 handlers on GAE python

我已經有一個使用webapp2構建的帶有GAE python的REST API。 我一直在查看protorpc和Cloud Enpoints中使用的protorpc消息,非常喜歡如何定義請求和響應。 有沒有辦法將其合並到我的webapp2處理程序中?

首先,我在webapp2方法上使用裝飾器。 我將裝飾器定義如下*:

    # Takes webapp2 request (self.request on baseHandler) and converts to defined protoRpc object 
    def jsonMethod(requestType, responseType, http_method='GET'):
            """
            NB: if both URL and POST parameters are used, do not use 'required=True' values in the protorpc Message definition 
                    as this will fail on one of the sets of parms
            """
            def jsonMethodHandler(handler):
                    def jsonMethodInner(self, **kwargs):            
                            requestObject = getJsonRequestObject(self, requestType, http_method, kwargs)

                            logging.info(u'request={0}'.format(requestObject))
                            response = handler(self, requestObject) # Response object       
                            if response:
                                # Convert response to Json
                                responseJson = protojson.encode_message(response)
                            else:
                                responseJson = '{}'
                            logging.info(u'response json={0}'.format(responseJson))
                            if self.response.headers:
                                    self.response.headers['Content-Type'] = 'application/json'
                            if responseJson:
                                    self.response.write(responseJson)
                                    self.response.write('')

                    return jsonMethodInner
            return jsonMethodHandler

jsonMethod裝飾器將protorpc消息用於'requestType'和'responseType'。 我已將http_method限制為方法的GET,POST或DELETE; 您可能希望更改此設置。 請注意,此修飾符必須應用於webapp2.RequestHandler類的實例方法(請參見下面的示例),因為它需要訪問webapp2請求和響應對象。

protorpc消息填充在getJsonRequestObject()中:

    def getJsonRequestObject(self, requestType, http_method, kwargs):
        "kwargs: URL keywords eg: /api/test/<key:\d+> => key"
        "request.GET: used for 'GET' URL query string arguments"
        "request.body: used for 'POST' or 'DELETE' form fields"
        logging.info(u'URL parameters: {0}'.format(kwargs))
        if http_method == 'POST' or http_method == 'DELETE':
            requestJson = self.request.body
            if requestJson == None:
                requestJson = '' # Cater for no body (eg: IE10)
            try:
                logging.info("Content type = {}".format(self.request.content_type))
                logRequest = requestJson if len(requestJson) < 1024 else requestJson[0:1024]
                try:
                    logging.info(u'Request JSON: {0}'.format(logRequest))
                except:
                    logging.info("Cannot log request JSON (invalid character?)")
                postRequestObject = protojson.decode_message(requestType, requestJson)
            except:
                logError()
                raise
            if self.request.query_string:
                # combine POST and GET parameters [GET query string overrides POST field]
                getRequestObject = protourlencode.decode_message(requestType, self.request.query_string)
                requestObject = combineRequestObjects(requestType, getRequestObject, postRequestObject)
            else:
                requestObject = postRequestObject

        elif http_method == 'GET':
            logging.info(u'Query strings: {0}'.format(self.request.query_string))
            requestObject = protourlencode.decode_message(requestType, self.request.query_string)
            logging.info(u'Request object: {0}'.format(requestObject))
        else:
            raise ValidationException(u'Invalid HTTP method: {0}'.format(http_method))
        if len(kwargs) > 0:      
            #Combine URL keywords (kwargs) with requestObject
            queryString = urllib.urlencode(kwargs)
            keywordRequestObject = protourlencode.decode_message(requestType, queryString)
            requestObject = combineRequestObjects(requestType, requestObject, keywordRequestObject)    

        return requestObject

getJsonRequestObject()處理GET,POST和webapp2 URL參數(注意:這些參數以kwargs輸入)。

CombineRequestObjects()合並requestType消息的兩個對象:

    def combineRequestObjects(requestType, request1, request2):
        """
        Combines two objects of requestType; Note that request2 values will override request1 values if duplicated
        """
        members = inspect.getmembers(requestType, lambda a:not(inspect.isroutine(a)))
        members = [m for m in members if not m[0].startswith('_')]
        for key, value in members:
                val = getattr(request2, key)
                if val:
                        setattr(request1, key, val)  
        return request1

最后,一個裝飾的webapp2方法示例:

    from protorpc import messages, message_types

    class FileSearchRequest(messages.Message):
        """
        A combination of file metadata and file information
        """
        filename = messages.StringField(1)
        startDateTime = message_types.DateTimeField(2)
        endDateTime = message_types.DateTimeField(3)

    class ListResponse(messages.Message):
        """
        List of strings response
        """
        items = messages.StringField(1, repeated=True)  

    ...

    class FileHandler(webapp2.RequestHandler):   
        @jsonMethod(FileSearchRequest, ListResponse, http_method='POST')  
        def searchFiles(self, request):
            # Can now use request.filename etc
            ...
            return ListResponse(items=items)

希望這將使您對如何實現自己的webapp2 / protorpc框架有所了解。

您還可以檢查並查看Cloud Endpoints如何實現其protorpc消息處理。 您可能還需要深入研究protorpc代碼本身。

  • 請注意,我已經嘗試簡化現有的實現,因此您可能會遇到在實現中需要解決的各種問題。 另外,諸如“ logError()”之類的方法和諸如“ ValidationException”之類的類是非標准的,因此您需要根據需要替換它們。 您可能還希望在某些時候刪除日志記錄。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM