i am trying to send a synchronized request to https server with esp8266 and i am using httpbin.org for testing purpose and i want to synchronize the requests. i mean how to not sending request until the previous is recieved and without using delay?
by comparing code (below) and result (below) you can see that httpsClient.readString() returns empty result from time to time. why? how to explain that? and how to fix that or get around it?
code and result are bellow. please help.
#include <ESP8266WiFi.h>
#include <WiFiClientSecure.h>
//i cut wifi ssid and pswrd declaration to shorten the question
const char *host = "httpbin.org"; //Domain to Server
String path = "/post"; //Path of Server
const int httpsPort = 443; //HTTPS PORT (default: 443)
WiFiClientSecure httpsClient;
String response;
void setup() {
//i cut wifi set up declaration to shorten the question
httpsClient.setInsecure();
if(httpsClient.connect(host, httpsPort)){
Serial.println("Connected to "+String(host));
}else
Serial.println("error connecting");
}
void loop() {
httpsClient.print(String("POST ") + "/response-headers" + " HTTP/1.1\r\n" +
"Host: " + "httpbin.com\r\n"+
"Content-Type: application/x-www-form-urlencoded\r\n" +
"Content-Length: 13\r\n\r\n" +
"say=Hi&to=Sam\r\n");
while(httpsClient.available()) {
response = httpsClient.readStringUntil('\n');
Serial.println(response);
}
Serial.println("---------------------------------------------------------");
}
Result:
---------------------------------------------------------
HTTP/1.1 200 OK
Date: Wed, 26 May 2021 16:20:01 GMT
Content-Type: application/json
Content-Length: 68
Connection: keep-alive
Server: gunicorn/19.9.0
Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true
{
"Content-Length": "68",
"Content-Type": "application/json"
}
---------------------------------------------------------
---------------------------------------------------------
HTTP/1.1 200 OK
Date: Wed, 26 May 2021 16:20:01 GMT
Content-Type: application/json
Content-Length: 68
Connection: keep-alive
Server: gunicorn/19.9.0
Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true
{
"Content-Length": "68",
"Content-Type": "application/json"
}
HTTP/1.1 200 OK
Date: Wed, 26 May 2021 16:20:01 GMT
Content-Type: application/json
Content-Length: 68
Connection: keep-alive
Server: gunicorn/19.9.0
Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true
{
"Content-Length": "68",
"Content-Type": "application/json"
}
---------------------------------------------------------
HTTP/1.1 200 OK
Date: Wed, 26 May 2021 16:20:02 GMT
Content-Type: application/json
Content-Length: 68
Connection: keep-alive
Server: gunicorn/19.9.0
Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true
{
"Content-Length": "68",
"Content-Type": "application/json"
}
---------------------------------------------------------
---------------------------------------------------------
---------------------------------------------------------
---------------------------------------------------------
---------------------------------------------------------
---------------------------------------------------------
HTTP/1.1 200 OK
Date: Wed, 26 May 2021 16:26:19 GMT
Content-Type: application/json
Content-Length: 68
Connection: keep-alive
Server: gunicorn/19.9.0
Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true
{
"Content-Length": "68",
"Content-Type": "application/json"
}
and so on.....
Related
i transform a payload need to send as as multipart/form to request.
the payload is like below
{
"goods_id": "12345,
"color_id_1": 20,
"image_id_1": vars.png1, //this is binary ,image data
"color_id_2": 11,
"image_id_2": vars.png1, //this is binary ,image data
}
here is sample file which we need to transform, the file is base on postman script.
in postman we can choose image file from notebook. in payload, the image is an object
which is stored in variable .
POST /cooperate/RegistAllImage HTTP/1.1
Content-Type: multipart/form-data; boundary=--------------------------549967118512544277394909
User-Agent: PostmanRuntime/7.29.0
Accept: */*
Cache-Control: no-cache
Postman-Token: ddddd
Host: ddddd
Accept-Encoding: gzip, deflate, br
Connection: keep-alive
Cookie: *****
Content-Length: 40980
----------------------------549967118512544277394909
Content-Disposition: form-data; name="goods_id"
Content-Type: application/x-www-form-urlencoded
12345
----------------------------549967118512544277394909
Content-Disposition: form-data; name="color_id_1"
Content-Type: application/x-www-form-urlencoded
20
----------------------------549967118512544277394909
Content-Disposition: form-data; name="image_1"; filename="064df7cefee0421990ccb74a5c1f9ccf.jpg"
Content-Type: application/octet-stream
<064df7cefee0421990ccb74a5c1f9ccf.jpg>
----------------------------549967118512544277394909
Content-Disposition: form-data; name="color_id_2"
Content-Type: application/x-www-form-urlencoded
2
----------------------------549967118512544277394909
Content-Disposition: form-data; name="image_2"; filename="064df7cefee0421990ccb74a5c1f9ccf.jpg"
Content-Type: application/octet-stream
<064df7cefee0421990ccb74a5c1f9ccf.jpg>
You can very well use the Multipart form module or can construct the parts using the script below.
%dw 2.0
import dw::module::Multipart
output multipart/form-data boundary="--------------------------549967118512544277394909"
---
{
parts: {
part1: Multipart::field({
name: "goods_id",
value: payload.goods_id,
mime: "appliation/x-www-form-urlencoded"
}),
part2: Multipart::field({
name: "color_id_1",
value: payload.color_id_1,
mime: "appliation/x-www-form-urlencoded"
})
,
part3: Multipart::field({
name: "image_id_1",
value: payload.image_id_1,
mime: "appliation/octet-stream",
fileName: "064df7cefee0421990ccb74a5c1f9ccf.jpg"
})
,
part4: Multipart::field({
name: "color_id_2",
value: payload.color_id_2,
mime: "appliation/x-www-form-urlencoded"
})
,
part5: Multipart::field({
name: "image_id_2",
value: payload.image_id_2,
mime: "appliation/octet-stream",
fileName: "064df7cefee0421990ccb74a5c1f9ccf.jpg"
})
}
}
Answer to the question in comment:
%dw 2.0
import dw::module::Multipart
output multipart/form-data boundary="--------------------------549967118512544277394909"
---
{
parts: payload mapObject ((value, key, index) -> {
("part" ++ ((index)+1)): Multipart::field({
"name": key as String,
"value": value as String,
"mime": if(key startsWith "image_id_") "application/octet-stream" else "application/x-www-form-urlencoded",
("fileName": "filenmae.png" )if(key startsWith "image_id_")
})
})
}
you can use the Multipart dataweave module that will make it fairly simple.
You will need Multipart::form function to create the form, and pass an array of all the fields, that you have in your payload. I have used pluck for it and then mapped it using Multipart:field function to get an Array of type MultipartPart. Your transform module will look like this
%dw 2.0
import dw::module::Multipart
output multipart/form-data
---
Multipart::form(
payload pluck ((value, key) ->
if(key as String startsWith "image_id_")
Multipart::field(key as String, value, "application/octet-stream")
else Multipart::field( key as String, value as String)
)
)
I have a question, I do not understand why the cookie is not added. I have a frontend and backend on separate servers and at various ports, I hit the backend for a token. In response, he gets it, however, it is not set. Could someone look? Secure and httpOnly is deactivated. On the frontend side I have set withCredentials: true.
On the frontend side:
axios.defaults.withCredentials = true;
axios.post('http://backendhost:8584/login', user).then(response => {
if(response){
this.props.history.push('/home');
}
});
Cors On the api side:
#Bean
CorsConfigurationSource corsConfiguration() {
CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true);
config.setAllowedOrigins(Collections.singletonList("*"));
config.setAllowedMethods(Collections.singletonList("*"));
config.setAllowedHeaders(Collections.singletonList("*"));
UrlBasedCorsConfigurationSource source =
new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", config);
return source;
}
Set cookie on the auth server side:
response.addCookie(generateCookie("session-token", customer.getToken()));
public Cookie generateCookie(String key, String value) {
Cookie cookie = new Cookie(key,value);
cookie.setMaxAge(60 * 60 * 24 * 365);
cookie.setSecure(false);
cookie.setHttpOnly(false);
cookie.setPath("/");
return cookie;
}
And I get it in chrome:
Access-Control-Allow-Credentials: true
Access-Control-Allow-Origin: http://frontendhost:8080
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Content-Type: application/json
Date: Tue, 16 Jun 2020 16:30:11 GMT
Expires: 0
Pragma: no-cache
Referrer-Policy: no-referrer
Set-Cookie: session-token=eyJhbGciOiJSUz; Max-Age=31536000; Expires=Wed, 16-Jun-2021 16:30:11 GMT; Path=/
transfer-encoding: chunked
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
X-Content-Type-Options: nosniff
X-Frame-Options: SAMEORIGIN
X-XSS-Protection: 1; mode=block
I am trying to send the Alert/Remainder via POSTMan to my skill.
Option 1: Authentication token API with Scope "alexa:skill_messaging"
POST /auth/o2/token HTTP/1.1
Host: api.amazon.com
Content-Type: application/x-www-form-urlencoded
User-Agent: PostmanRuntime/7.20.1
Accept: */*
Cache-Control: no-cache
Postman-Token: 2ae7afa3-c3f8-493f-b6e3-2db1e44e3a17,a4e45e8e-d0eb-4b3f-a612-e7d1959fdbe6
Host: api.amazon.com
Accept-Encoding: gzip, deflate
Content-Length: 236
Connection: keep-alive
cache-control: no-cache
grant_type=client_credentials&client_id=******************&client_secret=***********17a4f7b348982bdb4&scope=alexa%3Askill_messaging
Screenshote:
option 2: Authentication token API with Scope "alexa::alerts:reminders:skill:readwrite"
POST /auth/o2/token HTTP/1.1
Host: api.amazon.com
Content-Type: application/x-www-form-urlencoded
User-Agent: PostmanRuntime/7.20.1
Accept: */*
Cache-Control: no-cache
Postman-Token: 2ae7afa3-c3f8-493f-b6e3-2db1e44e3a17,c6765f77-6e35-419f-b614-780dae20ad4e
Host: api.amazon.com
Accept-Encoding: gzip, deflate
Content-Length: 236
Connection: keep-alive
cache-control: no-cache
grant_type=client_credentials&client_id=**************************&client_secret=************************&scope=alexa%3A%3Aalerts%3Areminders%3Askill%3Areadwrite
Step 2: Submitting the Alert request using token generated by Scope "alexa:skill_messaging" getting Invalide Bearer token
Let me know if I am missing anything and also where can find different scope for Alexa Authenictaion Token API
Unfortunately,
"That's a limitation of the Reminders API - you need to use the in-session access token to create reminders. You can run GET, UPDATE and DELETE operations out of session as well, so check this out for more information."
Only speaking with the device is possible get in-session access token to create reminders.
Out-session - Get reminders created by the skill (Skill Messaging API):
const IncomingMessageHandler = {
canHandle(handlerInput) {
const request = handlerInput.requestEnvelope.request;
return request.type === 'Messaging.MessageReceived'
},
async handle(handlerInput) {
const { requestEnvelope, context } = handlerInput;
console.log(`Message content: ${JSON.stringify(requestEnvelope.request.message)}`);
try {
const client = handlerInput.serviceClientFactory.getReminderManagementServiceClient();
const remindersResponse = await client.getReminders();
console.log(JSON.stringify(remindersResponse));
} catch (error) {
console.log(`error message: ${error.message}`);
console.log(`error stack: ${error.stack}`);
console.log(`error status code: ${error.statusCode}`);
console.log(`error response: ${error.response}`);
}
context.succeed();
}
}
https://developer.amazon.com/docs/smapi/alexa-reminders-api-reference.html#in-session-and-out-of-session-behavior-for-alexa-reminders-api
https://forums.developer.amazon.com/questions/196445/reminders-can-only-be-created-in-session.html#answer-196860
https://developer.amazon.com/pt-BR/docs/alexa/smapi/skill-messaging-api-reference.html
my draft with big Attachment.
create draft with gapi.
update this draft add some big file.
upload draft rawdata by resumable upload.
when i start a resumable session, it return 404.
Array
(
[url] => https://www.googleapis.com/resumable/upload/gmail/v1/users/me/drafts/r3718017142990379914
[method] => post
[http_header] => Array
(
[0] => Authorization: Bearer ya29.****
[1] => Content-type: application/json
[2] => X-Upload-Content-Type: message/rfc822
)
[response] => HTTP/1.1 200 Tunnel established
HTTP/1.1 404 Not Found
X-GUploader-UploadID: AEnB2Up-CJW9XP4E84DqWjZhI_8-YFgWR47UNNfqGkmM2S5EBf3H5aGOcuwHzLd-4faoKAxd_qgaO5GInDUiJx6uua8JDwj4X0yLamxA--WySFB3ZZxw7YQ
Vary: Origin
Vary: X-Origin
Content-Type: text/html; charset=UTF-8
Content-Length: 9
Date: Fri, 18 Aug 2017 12:48:24 GMT
Server: UploadServer
Alt-Svc: quic=":443"; ma=2592000; v="39,38,37,35"
Not Found
[res_header] => HTTP/1.1 200 Tunnel established
[res_body] => HTTP/1.1 404 Not Found
X-GUploader-UploadID: AEnB2Up-CJW9XP4E84DqWjZhI_8-YFgWR47UNNfqGkmM2S5EBf3H5aGOcuwHzLd-4faoKAxd_qgaO5GInDUiJx6uua8JDwj4X0yLamxA--WySFB3ZZxw7YQ
Vary: Origin
Vary: X-Origin
Content-Type: text/html; charset=UTF-8
Content-Length: 9
Date: Fri, 18 Aug 2017 12:48:24 GMT
Server: UploadServer
Alt-Svc: quic=":443"; ma=2592000; v="39,38,37,35"
Not Found
[errno] => 0
[error] =>
)
so, is the draft can not edited using a resumable upload?
How can I edit a draft with a large attachment?
when you update draft, it must used put.
like:
PUT https://www.googleapis.com/upload/gmail/v1/users/me/drafts/r6052444812129220058
I'm trying to call a REST API running locally using AngularJS. Here is the AngularJS code :
$http.defaults.headers.common = {"Access-Control-Request-Headers": "accept, origin, authorization"};
$http.defaults.headers.common['Authorization'] = 'Basic amF5M2RlYzpqYXk=';
$http({method: 'GET', url: 'http://127.0.0.1:5000/user/jay3dec'}).
success(function(data, status, headers, config) {
}).
error(function(data, status, headers, config) {
alert(data);
});
But I'm getting an errors in the browser console :
Refused to set unsafe header "Access-Control-Request-Headers"
I tried to query call the REST API running at http://127.0.0.1:5000/user/jay3dec using CURL.
curl -H "Origin: http://127.0.0.1:8000" -H "Authorization: Basic amF5M2RlYzpqYXk=" http://127.0.0.1:5000/user/jay3dec --verbose
And it gave the following output :
> GET /user/jay3dec HTTP/1.1
> User-Agent: curl/7.35.0
> Host: 127.0.0.1:5000
> Accept: */*
> Origin: http://127.0.0.1:8000
> Authorization: Basic amF5M2RlYzpqYXk=
>
* HTTP 1.0, assume close after body
< HTTP/1.0 200 OK
< Content-Type: application/json
< Content-Length: 454
< ETag: bff7b7db33baedb612276861e84faa8f7988efb1
< Last-Modified: Tue, 30 Dec 2014 14:32:31 GMT
< Access-Control-Allow-Origin: *
< Access-Control-Allow-Headers: Authorization
< Access-Control-Allow-Methods: HEAD, OPTIONS, GET
< Access-Control-Allow-Max-Age: 21600
< Server: Eve/0.4 Werkzeug/0.9.6 Python/2.7.6
< Date: Sun, 25 Jan 2015 20:00:29 GMT
<
* Closing connection 0
{"username": "jay3dec", "_updated": "Tue, 30 Dec 2014 14:32:31 GMT", "password": "jay", "firstname": "jay", "lastname": "raj", "phone": "9895590754", "_links": {"self": {"href": "/user/54a2b77f691d721ee170579d", "title": "User"}, "parent": {"href": "", "title": "home"}, "collection": {"href": "/user", "title": "user"}}, "_created": "Tue, 30 Dec 2014 14:32:31 GMT", "_id": "54a2b77f691d721ee170579d", "_etag": "bff7b7db33baedb612276861e84faa8f7988efb1"}
Can any one spot what may be the issue ??
The code behind $http.defaults.headers.common is
var xhr = createXhr();
xhr.open(method, url, true);
forEach(headers, function(value, key) {
if (isDefined(value)) {
xhr.setRequestHeader(key, value);
}
});
...
function createXhr() {
return new window.XMLHttpRequest();
}
Referring to XMLHttpRequest specification , browser will terminate if header is a case-insensitive match for one of the following headers
Accept-Charset
Accept-Encoding
Access-Control-Request-Headers
Access-Control-Request-Method
Connection
Content-Length
...
That's why you can't use $http.defaults.headers.common to set Access-Control-Request-Headers header. Browser will handle request headers for you instead.
The problem is in CORS
You should make configure your server side to allow Authorization in header. I don't know what you are used for server but for my asp.net web api 2 server it look like:
Web.config
<system.webServer>
<httpProtocol>
<customHeaders>
<add name="Access-Control-Allow-Origin" value="*" />
<add name="Access-Control-Allow-Headers" value="Content-Type,Authorization" />
<add name="Access-Control-Allow-Methods" value="GET, POST, PUT, DELETE, OPTIONS" />
</customHeaders>
</httpProtocol>
......
For security reasons, browsers do not allow head has set some security risks, such as cookie, host, referer, etc. So, do not use the browser to parse the line head. It can be used on the server side set of agency sent.
Reference: Cross origin resource sharing