Kong / kong

🦍 The Cloud-Native API Gateway and AI Gateway.
https://konghq.com/install/#kong-community
Apache License 2.0
38.95k stars 4.78k forks source link

strip_request_path doesn't seen to work with request_host #1056

Closed francisco-andrade closed 8 years ago

francisco-andrade commented 8 years ago

Hi there,

I'm using Kong 0.7.0 and I'm having some problems when registering an api with strip_request_path=true and request_host. Kong doesn't seen to be removing the request_path like it do when we create an api without request_host parameter.

For example: 1- Register an api with request_path and without request_host: bq. curl -i -X POST --url http://localhost:8012/apis --data 'name=test1' --data 'upstream_url=http://localhost:8080/restheart' --data 'request_path=/test1' --data 'strip_request_path=True'

2- Test API: bq. curl -i -X GET --url 'http://localhost:8000/test1/database/collection' the api gets: /restheart/database/collection (without the test1)

3- Register an api with request_path and request_host: bq. curl -i -X POST --url http://localhost:8012/apis --data 'name=test2' --data 'upstream_url=http://localhost:8080/restheart' --data 'request_host=test.local.com' --data 'request_path=/test2' --data 'strip_request_path=True'

4- Test API: bq. curl -i -X GET --url 'http://test.local.com:8000/test2/database/collection' the api gets: /restheart/test2/database/collection

As shown in my example, kong is able to drive the request to the api, but it won't strip the request_path registered on the api creation.

Is this a bug or it is expected to work like this?

Regards, Francisco Andrade

thibaultcha commented 8 years ago

This is currently expected, since request_host has the priority over request_path when routing a request. strip_request_path is only triggered when routing happens with the request_path. You could remove the request_host to make routing happen with the path, especially since having both does not provide any additional behavior.

francisco-andrade commented 8 years ago

Ok. Thanks very much for the explanation :)

Just as an enhancement suggestion, when someone tries to register an API using these combination, Kong could warn about its behavior and/or register strip_request_path as false instead of registering as true:

{ "upstream_url": "http://localhost:8080/restheart", "request_path": "/test2", "id": "cf864af5-b6a9-43d0-8df7-fc04d7ca7f26", "strip_request_path": true, "name": "test2", "created_at": 1457555076000, "request_host": "test.local.com" }

subnetmarco commented 8 years ago

Closing this since it's not an issue.

adamlc commented 8 years ago

I think this should at least be documented somewhere as I've just spent an hour or so trying to figure out whats going on. I think people would assume the options would work regardless of which options have been set.

I was hoping to have different API hosted on 1 URL with different request paths, but it seems like this won't be possible.

thibaultcha commented 8 years ago

This is indeed documented in the proxy reference.

pulyaevskiy commented 8 years ago

@thibaultcha could you point at where exactly is this documented? In the Proxy reference docs I couldn't find any explicit statements that DNS and request_path are mutually exclusive.

I feel like this should be written in bold capital red letters somewhere at the top of that doc. I'm exaggerating of course, but the point is - this is basically a blocker for us now, after we spent some time and resources on this otherwise great tool.

If I understand this correctly then if someone has multiple DNSs + routing based on request prefix they would have to setup separate Kong cluster for each DNS and have request_path routing configured separately on each?

pulyaevskiy commented 8 years ago

Also, it seems this can be workarounded by having Kong proxy to itself first.

E.g. having something like:

my-specific-api.com/my-path => all-my-apis.com/my-specific-api/my-path

So that first it matches by DNS and forwards to "catch all" DNS which then routes by request path.

@thibaultcha would this approach be a "good" or "bad" practice in such cases?

saithala commented 8 years ago

@pulyaevskiy I have the same problem. Could you please let me know how you resolved this? I too spent some time having both request_host and request_path was wondering why it was not working. The other problem I have is, I have an Oauth2 plugin configured to APIs, since I have 2 APIs, I cannot have the same request_host to both the APIs. After I did this, I'm not getting the oauth2 token. Any ideas ?

pulyaevskiy commented 8 years ago

@saithala

Assume you have two public DNS great-api.example.com and awesome-api.example.com. Within each DNS you'd want to route requests based on path prefix to different backend services.

To make this work you'd have to have another "catch-all" DNS, e.g. api.example.com which is served by your Kong server as well. Then just add two API definitions on Kong for your great and awesome APIs like this:

{
    "name": "great_api",
    "request_host": "great-api.example.com",
    "preserve_host": false,
    "strip_request_path": false,
    "upstream_url": "http://api.example.com/great-api"
}

{
    "name": "awesome_api",
    "request_host": "awesome-api.example.com",
    "preserve_host": false,
    "strip_request_path": false,
    "upstream_url": "http://api.example.com/awesome-api"
}

So, a request like GET great-api.example.com/crm/users/123 would be routed to api.example.com/great-api/crm/users/123.

Now, if you have a dedicated backend CRM service handling all /crm/* endpoints for your great-api you just need to add following API definition to Kong:

{
    "name": "greate_api_crm",
    "request_path": "/great-api/crm",
    "preserve_host": false,
    "strip_request_path": true,
    "upstream_url": "http://your-internal-crm-service-host:8080"
}

So your api.example.com/great-api/crm/users/123 would be routed to http://your-internal-crm-service-host:8080/users/123.

This adds an extra network hop. But the benefit is that you can attach all the necessary plugins for auth, cors, rate limiting and whatnot to the two top-level API definitions created as the first step above.

saithala commented 8 years ago

Thanks for the explanation @pulyaevskiy

saithala commented 8 years ago

@pulyaevskiy I do not have the luxury of having multiple public dns. Need to think of other options.

Other questions I had

1) In the scenario you explained above, is there a way to have a single oauth2 token url for all APIs? Right now since I have the request_path configured while adding the API, I need to append that in the token url too. for example if the request_path for a API is /something, then to get the oauth2 token using client credentials flow, the url would be /something/oauth2/token. Similarly each API added with a different request_path would have its own token url. Any ideas how we can avoid this? 2) I need to add another API which needs to be unauthenticated. Even though I did not add the oauth2 plugin on top of this, it still asks for a token everytime I access it. Dont understand why.