Has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource

Hi all,
I know these similar question has been asked over and over again. But I really cannot figure out which part I did wrong. I am working on API Gateway with Python and I received this error. The serverless.yml and my handler is below. Any help can be appreciated.

service: model-service
plugins:
    - serverless-python-requirements
    - serverless-domain-manager
    - serverless-plugin-warmup
custom:
    pythonRequirements:
        dockerizePip: non-linux
    env:
        PROD_DB: string
        DEMO_DB: string
        NLTK_DATA: '/opt/nltk_data'
        appId: XXX
        appSecret: xxx

    customDomain:
        domainName: string
        certificateName: string
        basePath: api
        stage: '${self:provider.stage}'

    authorizer:
        auth:
            name: authFunc
            type: token
            identitySource: method.request.header.Authorization
            #resultTtlInSeconds: 0
    
    warmup:
        enable: true
        #events: 
            #- schedule: 'cron(0/5 8-17 ? * MON-FRI *)'
        concurrency: 5

resources:
    Resources:
        AuthFailureGatewayResponse:
            Type: 'AWS::ApiGateway::GatewayResponse'
            Properties: {ResponseParameters: {gatewayresponse.header.Access-Control-Allow-Origin: '''*''', gatewayresponse.header.Access-Control-Allow-Headers: '''*'''}, ResponseType: UNAUTHORIZED, RestApiId: {Ref: ApiGatewayRestApi}, StatusCode: '401'}
			        
provider:
    name: aws
    runtime: python3.7
    region: ap-southeast-2
    stage: prod
    resourcePolicy:
        -   Effect: Allow
            Principal: "*"
            Action: "execute-api:Invoke"
            Resource: "execute-api:/*"
    iamRoleStatements:
        -   Effect: "Allow"
            Action:
                - "lambda:InvokeFunction"
            Resource: "*"
package:
    exclude:
        - venv/**
        - node_modules/**
        - nltk/**
functions:
    distractibility_index:
        handler: handler.di_handler
        environment:
            PROD_DB: '${self:custom.env.PROD_DB}'
            DEMO_DB: '${self:custom.env.DEMO_DB}'
        vpc:
            securityGroupIds: string
            subnetIds: string
        events:
            - http:
                cors: true
                method: post
                path: di
                authorizer: '${self:custom.authorizer.auth}'
        timeout: 30
        warmup:
            true    
    search_skill:
        handler: handler.search_skill_handler
        environment:
            PROD_DB: '${self:custom.env.PROD_DB}'
            DEMO_DB: '${self:custom.env.DEMO_DB}'
        events:
            - http:
                cors: true
                method: post
                path: searchskill
                authorizer: '${self:custom.authorizer.auth}'
        vpc:
            securityGroupIds: string
            subnetIds: string
        timeout: 30
        warmup:
            true        
    word_cloud:
        handler: handler.word_cloud_handler
        environment:
            PROD_DB: '${self:custom.env.PROD_DB}'
            DEMO_DB: '${self:custom.env.DEMO_DB}'
            NLTK_DATA: '${self:custom.env.NLTK_DATA}'
        events:
            - http:
                cors: true
                method: post
                path: wordcloud
                authorizer: '${self:custom.authorizer.auth}'
        layers: 
            - {Ref: NltkLambdaLayer}
        vpc:
            securityGroupIds: [sg-5cbc6239]
            subnetIds: [subnet-d258f6b5, subnet-1f444046]
        timeout: 30
        warmup:
            true        
    token:
        handler: handler.token_handler
        environment:
            PROD_DB: '${self:custom.env.PROD_DB}'
            DEMO_DB: '${self:custom.env.DEMO_DB}'
            appId: '${self:custom.env.appId}'
            appSecret: '${self:custom.env.appSecret}'
        events:
            - http:
                cors: true
                method: post
                path: token
        vpc:
            securityGroupIds: string
            subnetIds: string
        timeout: 30
        warmup:
            true                    
    authFunc:
        handler: handler.auth_handler
        environment:
            PROD_DB: '${self:custom.env.PROD_DB}'
            DEMO_DB: '${self:custom.env.DEMO_DB}'
            appId: '${self:custom.env.appId}'
            appSecret: '${self:custom.env.appSecret}'
        cors: true
        warmup:
            true
layers:
    nltk:
        path: nltk
        name: NltkData # optional, Deployed Lambda layer name
        description: Nltk data # optional, Description to publish to AWS
        compatibleRuntimes: # optional, a list of runtimes this layer is compatible with
            - python3.7
        licenseInfo: GPLv3 # optional, a string specifying license information
        allowedAccounts: # optional, a list of AWS account IDs allowed to access this layer.
            - '*'
        retain: false # optional, false by default. If true, layer versions are not deleted as new ones are created

Python:

def word_cloud_handler(event, context):
	if(event.get("source")=="serverless-plugin-warmup"):
	   return warm_up()
	parameters = json.loads(event.get("body"))
	service.db_config(get_connection_string(parameters))
	data = service.find_world_cloud(parameters)
	return {"statusCode": 200, "headers":{'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Credentials': True}, "body": data}

Do you actually reach the return part of your handler code? It could be that something goes wrong, the framework tries to return status 500 or similar, and then the CORS error appears because you do not catch exception and no CORS header for other status than http 200.

If I were you I would try and debug to see which line in your code is reached, if any.

and further to @montao, have you authenticated with your custom authorizer?

@goldie
I agree that the authorizor may be the problem for the original poster. Or did you actually mean my authorizer (but that is not part of the problem or is it)?

em, thanks for your reply and sorry for my late reply. Can u explain more about authorizor may be the problem? The custom authorizor use some id and secret to generate a token via jwt library. And I think the code should be alright, as when I use postman with same header and body, it works properly.

BTW, the serverless.tml and handler looks fine right?

I think you need to add some logging and, as @montao suggested, see if you ever get to the return statement. I have had this problem with a custom authorizer where auth was failing before even the lambda executed and it looked like a CORS error from the outside.

Sorry, I meant the OP’s authorizer. I’ve seen this kind of problem before.

Thx for you reply. I added few logs in custom authorizer and lambda function, it turns out they are not executed at all. It might be some other issues. I am trying to figure out with our front-end developer. Thx for your advice.