I have integrated my k8s deployment with google endpoints. I have 12 services out of which 11 services are working fine with google endpoints except for one service. When its transferring requests to application container its ignoring the header values with underscore.
Implementation
I have added this in my application deployment (Ignore syntax i have it in correct format in deployment)
- args:
- --http_port
- "8081"
- --backend
- 127.0.0.1:8080
- --service
- <MY_ENDPOINT>
- --service_account_key
- /etc/nginx/creds/<MY_CREDS>
- --rollout_strategy=managed
image: gcr.io/endpoints-release/endpoints-runtime:1
imagePullPolicy: Always
name: esp
ports:
- containerPort: 8081
protocol: TCP
resources: {}
volumeMounts:
- mountPath: /etc/nginx/creds
name: service-account-creds
readOnly: true
Here in the below sample, i have sent two headers with TEST-CODE and TEST_CODE. Both are getting received at the application end when i am sending request via application port, but when i access it via esp port, i receive only header with -(hyphen) not with _(underscore). TEST-CODE is being received in the server but not TEST_CODE, when accessing via esp.
When i am sending request to my application using curl or postman via 8080 which is application port
curl -XPOST http://localhost:8080/<CONTEXT_PATH> -H "Content-Type: application/json" -H "USER-ID: abc" -H "TEST-CODE: xyz" -H "TEST_CODE: wxyz"
I get response like this
{
"timestamp": "2020-04-05T19:42:44.958564Z",
"principal": null,
"session": null,
"request": {
"method": "POST",
"uri": "http://localhost:8080/<MY_URL>",
"headers": {
"host": [
"localhost:8080"
],
"test-code": [
"xyz"
],
"content-type": [
"application/json"
],
"x-user-id": [
"abc"
],
"test_code": [
"wxyz"
],
"user-agent": [
"curl/7.52.1"
],
"accept": [
"*/*"
]
},
"remoteAddress": null
},
"response": {
"status": 200,
"headers": {
"Content-Length": [
"435"
],
"Date": [
"Sun, 05 Apr 2020 19:42:45 GMT"
],
"Content-Type": [
"application/json;charset=UTF-8"
]
}
},
"timeTaken": 633
}
When i am sending request to my application using curl or postman via 8081 which is via esp
curl -XPOST http://localhost:8081/<CONTEXT_PATH>?key=<MY_KEY> -H "Content-Type: application/json" -H "USER-ID: abc" -H "TEST-CODE: xyz" -H "TEST_CODE: wxyz"
I get response like this
{
"timestamp": "2020-04-05T19:42:57.102184Z",
"principal": null,
"session": null,
"request": {
"method": "POST",
"uri": "http://localhost/<MY_URL>?<MY_KEY>",
"headers": {
"x-real-ip": [
"127.0.0.1"
],
"x-google-real-ip": [
"127.0.0.1"
],
"x-cloud-trace-context": [
"<MY_GOOGLE_TRACE_CONTEXT>"
],
"host": [
"localhost"
],
"test-code": [
"xyz"
],
"x-endpoint-api-project-id": [
"<MY_ENDPOINT_PROJECT_ID>"
],
"content-type": [
"application/json"
],
"x-forwarded-for": [
"127.0.0.1"
],
"x-user-id": [
"abc"
],
"user-agent": [
"curl/7.52.1"
],
"accept": [
"*/*"
]
},
"remoteAddress": null
},
"response": {
"status": 400,
"headers": {
"Connection": [
"close"
],
"Content-Length": [
"256"
],
"Date": [
"Sun, 05 Apr 2020 19:42:57 GMT"
],
"Content-Type": [
"application/json"
]
}
},
"timeTaken": 21
}
Again,
Notice the difference : I am sending test code header as TEST-CODE and TEST_CODE, both are coming when i am accessing via application port, but when i am accessing via esp container, the application is receiving TEST-CODE alone, not TEST_CODE.
I have tried some other HEADERS with -(hyphen) and some with _(underscore). Every time headers with -(hyphen) is being received via esp to application but not with _(underscore).
I have took the above responses from spring actuator endpoints (actuator/httptrace)
Can someone help?
Related
I have follow logs in kibana
{
"_index": "crashlytics-prod-b2c-20220628",
"_type": "log",
"_id": "qPlIqoEB1i589BiuiYcG",
"_version": 1,
"_score": null,
"fields": {
"entity_id.keyword": [
""
],
"app_version.keyword": [
""
],
"device.keyword": [
"mobile"
],
"level": [
1
],
"entity_type.keyword": [
"null"
],
"message": [
"{request: {data: {content-type: application/json, AppVersion: 2.1.0, content-length: 42}, url: https://api.test.com/api/v1/auth/refresh}, error: Http status error [400], data: {timestamp: 2022-06-28T12:28:09.167Z, status: 400, errorData: [{field: push, message: Invalid refresh token, code: }]}, payload: {Settings: {deviceId: 13913338519391707838, magentoUserId: null}, ..."],
A message contains info about app version (AppVersion: 2.1.0) in this case.
Is there way to vizualizate data based on AppVersion info,
in simle way it could be looks like
AppVersion: 2.1.0 - 90 logs row
AppVersion: 2.0.0 - 20 logs row
AppVersion: 1.9.0 - 10 logs row
I am trying to populating an empty field by using patch method in Contentful. The following piece of code works in one cloned environment but does not work in another.
let patchData: OpPatch[] = [
{
op: 'replace',
path: '/fields/keywords',
value: entryKeyword,
},
];
await cmaClient.entry.patch({ entryId: entryId }, patchData, { 'X-Contentful-Version': entryVersion });
When I try to execute this, receiving a 'Unprocessable Entity' error:
UnprocessableEntity: {
"status": 422,
"statusText": "Unprocessable Entity",
"message": "Could not apply patch to entry: invalid patch",
"details": {},
"request": {
"url": "/spaces/xyz/environments/abc/entries/123456789",
"headers": {
"Accept": "application/json, text/plain, */*",
"Content-Type": "application/json-patch+json",
"X-Contentful-User-Agent": "sdk contentful-management-plain.js/7.54.2;",
"Authorization": "Bearer ...",
"user-agent": "node.js/v14.19.2",
"Accept-Encoding": "gzip",
"X-Contentful-Version": 25,
"Content-Length": 78
},
"method": "patch",
"payloadData": "[{\"op\":\"replace\",\"path\":\"/fields/keywords\",\"value\":\"test keyword\"}]"
},
"requestId": "abcd-123456"
}
I have the same exact access permissions to both environments. What am I missing out on?
I had the same issue - turned out when the entry doesn't have the filed you're trying to patch - it will throw an error like above.
I have a reverse proxy server with NGINX and I want to test its configuration automatically.
What I want to achieve in the end is to have a command that I can run, it starts the NGINX with the configuration, run several http requests, and then track and gather whether the right proxied server was called.
I've been thinking on setting up an environment with docker-compose and use curl/wget with the list of urls I want to test. The thing that I don't know is how to mock certain domains and track the forwarded requests.
Is there a tool to do that or should I write a server manually?
After experimenting a bit I managed to create this solution.
Use Docker Compose, Wiremock and Newman. The idea is to setup NGINX proxying requests to Wiremock (where you can control if the request matched the right structure), then with Newman, you can run a Postman collection that automatically checks that the stubbed responses are the right ones.
Example
Create all these files in a folder, get the testing environment by running
docker-compose up -d nginx wiremock
and then, to run the test suite
docker-compose run --rm newman
It should print the results of the collection.
Files
docker-compose.yml
version: "3"
services:
nginx:
image: nginx
ports:
- "80:80"
volumes:
- ./config:/etc/nginx
wiremock:
image: wiremock/wiremock:2.32.0
command: [ "--port", "80", "--verbose" ]
ports:
- "8080:80"
volumes:
- ./wiremock:/home/wiremock
networks:
default:
aliases:
- backend-service-1
- backend-service-2
newman:
image: postman/newman
volumes:
- ./newman:/etc/newman
command: [ "run", "example.postman_collection.json" ]
config/nginx.conf
events {
worker_connections 1024;
}
http {
resolver 127.0.0.11; # docker internal resolver
server {
listen 80 default_server;
location /some/path/ {
proxy_set_header X-Forwarded-Host $host;
proxy_pass http://backend-service-1/some/path;
}
location /other/path/ {
proxy_set_header X-Forwarded-Host $host;
proxy_pass http://backend-service-2/other/path;
}
}
}
wiremock/mappings/some-path.json
{
"request": {
"method": "GET",
"url": "/some/path",
"headers": {
"Host": {
"equalTo": "backend-service-1",
"caseInsensitive": true
}
}
},
"response": {
"status": 200,
"body": "{\"host\": \"from-1\"}",
"headers": {
"Content-Type": "application/json"
}
}
}
wiremock/mappings/other-path.json
{
"request": {
"method": "GET",
"url": "/other/path",
"headers": {
"Host": {
"equalTo": "backend-service-2",
"caseInsensitive": true
}
}
},
"response": {
"status": 200,
"body": "{\"host\": \"from-2\"}",
"headers": {
"Content-Type": "application/json"
}
}
}
newman/example.postman_collection.json
{
"info": {
"name": "example",
"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
},
"item": [
{
"name": "some path",
"event": [
{
"listen": "test",
"script": {
"exec": [
"pm.test(\"request backend service 1\", function () {",
" pm.response.to.have.status(200);",
"",
" var jsonData = pm.response.json();",
" pm.expect(jsonData.host).to.eql(\"from-1\");",
"});",
""
],
"type": "text/javascript"
}
}
],
"request": {
"method": "GET",
"header": [],
"url": {
"raw": "http://nginx/some/path/",
"protocol": "http",
"host": [
"nginx"
],
"path": [
"some",
"path",
""
]
}
},
"response": []
},
{
"name": "other path",
"event": [
{
"listen": "test",
"script": {
"exec": [
"pm.test(\"request backend service 2\", function () {",
" pm.response.to.have.status(200);",
"",
" var jsonData = pm.response.json();",
" pm.expect(jsonData.host).to.eql(\"from-2\");",
"});",
""
],
"type": "text/javascript"
}
}
],
"request": {
"method": "GET",
"header": [],
"url": {
"raw": "http://nginx/other/path/",
"protocol": "http",
"host": [
"nginx"
],
"path": [
"other",
"path",
""
]
}
},
"response": []
}
]
}
I have implemented Ocelot API gateway in my project which was working fine for 'GET' requests but when I tried to send 'POST' request I am getting the error:
previousRequestId: no previous request id, message: Error Code: UnableToFindDownstreamRouteError Message: Failed to match ReRoute configuration for upstream path: /api/patient/CreateAppointment, verb: POST. errors found in ResponderMiddleware. Setting error response for request path:/api/patient/CreateAppointment, request method: POST
Following is my ocelot.json:
{
"Routes": [
{
"DownstreamPathTemplate": "/api/patient/{everything}",
"DownstreamScheme": "http",
"DownstreamHostAndPorts": [
{
"Host": "patientservice",
"Port": 81
}
],
"UpstreamPathTemplate": "/api/patient/{everything}",
"UpstreamHttpMethod": [ "GET", "POST" ],
"UpstreamHost": "*"
},
{
"DownstreamPathTemplate": "/api/actor",
"DownstreamScheme": "http",
"DownstreamHostAndPorts": [
{
"Host": "postgresqldapper",
"Port": 5001
}
],
"UpstreamPathTemplate": "/api/actor",
"UpstreamHttpMethod": [ "GET" ]
},
{
"DownstreamPathTemplate": "/api/product/{everything}",
"DownstreamScheme": "http",
"DownstreamHostAndPorts": [
{
"Host": "productservice",
"Port": 80
}
],
"UpstreamPathTemplate": "/api/product/{everything}",
"UpstreamHttpMethod": [ "GET" ]
},
{
"DownstreamPathTemplate": "/api/weatherforecast",
"DownstreamScheme": "http",
"DownstreamHostAndPorts": [
{
"Host": "postgresqldapper",
"Port": 5001
}
],
"UpstreamPathTemplate": "/api/weatherforecast",
"UpstreamHttpMethod": [ "GET" ]
},
{
"DownstreamPathTemplate": "/api/user",
"DownstreamScheme": "http",
"DownstreamHostAndPorts": [
{
"Host": "loginservicedapr",
"Port": 80
}
],
"UpstreamPathTemplate": "/api/user",
"UpstreamHttpMethod": [ "GET" ]
},
{
"DownstreamPathTemplate": "/api/user/{everything}",
"DownstreamScheme": "http",
"DownstreamHostAndPorts": [
{
"Host": "loginservicedapr",
"Port": 5001
}
],
"UpstreamPathTemplate": "/api/user/{id}",
"UpstreamHttpMethod": [ "GET" ]
}
],
"GlobalConfiguration": {
"RequestIdKey": "OcRequestId",
"AdministrationPath": "/administration"
}
}
The API to which I am doing the 'POST' request is working fine for the 'POST' request when invoked directly from Swagger or Postman.
Please let me know what I should change in ocelot.json file so that the 'POST' request can through?
Your error is effectively saying that Ocelot is unable to route requests to
POST /api/patient/CreateAppointment
In your screenshot, your curl command (which is working) is a request to:
POST /api/patient
Your /{everything} path suffix is telling Ocelot that whatever suffix you call into the gateway with will be present on the downstream service.
My theory is that you have not defined a CreateAppointment endpoint operation on your downstream patient service API. Once you define this path on your service, your /api/patient/{everything} route mapping should work fine.
I know that curl can post data to a URL:
$ curl -X POST http://httpbin.org/post -d "hello"
{
"args": {},
"data": "",
"files": {},
"form": {
"hello": ""
},
"headers": {
"Accept": "*/*",
"Content-Length": "5",
"Content-Type": "application/x-www-form-urlencoded",
"Host": "httpbin.org",
"User-Agent": "curl/7.50.1"
},
"json": null,
"origin": "64.238.132.14",
"url": "http://httpbin.org/post"
}
And I know I can pipe to curl to achieve the same thing:
$ echo "hello" | curl -X POST http://httpbin.org/post -d #-
{
"args": {},
"data": "",
"files": {},
"form": {
"hello": ""
},
"headers": {
"Accept": "*/*",
"Content-Length": "5",
"Content-Type": "application/x-www-form-urlencoded",
"Host": "httpbin.org",
"User-Agent": "curl/7.50.1"
},
"json": null,
"origin": "64.238.132.14",
"url": "http://httpbin.org/post"
}
Now here is where it gets tricky. I know about http transfer-coding and chunking, for example to send a multiline file:
('silly' is a file that contains several lines of text, as seen here)
$ cat silly | curl -X POST --header "Transfer-Encoding: chunked" "http://httpbin.org/post" --data-binary #-
{
"args": {},
"data": "",
"files": {},
"form": {
"hello\nthere\nthis is a multiple line\nfile\n": ""
},
"headers": {
"Accept": "*/*",
"Content-Length": "41",
"Content-Type": "application/x-www-form-urlencoded",
"Host": "httpbin.org",
"User-Agent": "curl/7.50.1"
},
"json": null,
"origin": "64.238.132.14",
"url": "http://httpbin.org/post"
}
Now what I want to be able to do is to have curl read a line from stdin, send it as a chunk, and then come back and read stdin again (which allows me to keep it going continously). This was my first attempt:
curl -X POST --header "Transfer-Encoding: chunked" "http://httpbin.org/post" -d #-
And it does work ONE TIME ONLY when I hit ctrl-D, but that obviously ends the execution of curl.
Is there any way to tell curl "Send (using chunk encoding) what I've given you so far, and then come back to stdin for more" ?
Thanks so much, I've been scratching my head for a while on this one!