Related
I have an Azure Function written in JS, which is triggered by the Service Bus and generates files to Blob Storage. When I'm trying to return an HTTP result I'm receiving the error as below:
System.Private.CoreLib: Exception while executing function: Functions.categoryMessageConsumer. Microsoft.Azure.WebJobs.Script: Unable to cast object of type 'System.String' to type 'Microsoft.AspNetCore.Http.HttpRequest'.
I don't know why the result is trying to be mapped to the HttpRequest object.
index.ts:
import { AzureFunction, Context, HttpRequest } from '#azure/functions';
...
const serviceBusTopicTrigger: AzureFunction = async function(context: Context, req: HttpRequest) {
let categoryMessage: CategoryMessage = Object.assign(new CategoryMessage(), req);
let messageValidationResult = await categoryMessage.validate();
if(!messageValidationResult.isValid) {
context.log.error(messageValidationResult.errors);
return {
status: 400,
body: "Unexpected error"
};
}
...
}
function.json output binding:
...
{
"type": "http",
"direction": "out",
"name": "$return"
}
...
host.json
{
"version": "2.0",
"logging": {
"applicationInsights": {
"samplingSettings": {
"isEnabled": true,
"excludedTypes": "Request"
}
}
},
"extensionBundle": {
"id": "Microsoft.Azure.Functions.ExtensionBundle",
"version": "[1.*, 2.0.0)"
}
}
var http = require('https');
module.exports = function (context, eventHubMessages) {
context.log(`JavaScript eventhub trigger function called for message array ${eventHubMessages}`);
eventHubMessages.forEach((message, index) => {
function callService(msg) {
let promise = new Promise((resolve, reject) => {
var options = {
host: process.env["HOST"],
port: process.env["PORT"],
path: process.env["PATH"],
method: process.env["WEBSERVICE_METHOD"],
headers: {
'Content-Type': process.env["WEBSERVICE_CONTENT_TYPE"],
'x-api-key' : process.env["WEBSERVICE_API_KEY"]
}
};
var response = '';
const request = http.request(options, (res) => {
res.on('data', (d) => {
response += d;
})
res.on('end', (d) => {
context.res = {
body: response
};
resolve(response);
})
});
request.on('error', (error) => {
context.log.error(error);
reject(error);
context.done();
})
request.write(msg);
request.end();
});
promise.then((response) => {
context.log(`mensagge send: ${msg}`);
context.log(`response: ${response}`);
context.done();
});
}
callService(message);
});
};
It was my index.js
and now it is my function.js:
{
"bindings": [
{
"type": "eventHubTrigger",
"name": "eventHubMessages",
"direction": "in",
"eventHubName": "event-hub-name",
"connection": "CONNECTION_EVENT_HUB",
"cardinality": "many",
"consumerGroup": "$Default",
"dataType": "string"
},
{
"type": "http",
"direction": "out",
"name": "$return"
}
]
}
and in the local.settings.json I declared all of the environment vars like HOST, PORT, CONNECTION_EVENT_HUB, etc.
This is because, your function is probably trying to create another object which it did not expect.
As you have mentioned the response variable name as $return and it is expecting that. Rather than this, code your function like below:
function.json:
{
"disabled": false,
"bindings": [
{
"authLevel": "function",
"type": "httpTrigger",
"direction": "in",
"name": "req"
},
{
"type": "http",
"direction": "out",
"name": "res"
}
]
}
JS code:
module.exports = function(context, req) {
context.log('Node.js HTTP trigger function processed a request. RequestUri=%s', req.originalUrl);
if (req.query.name || (req.body && req.body.name)) {
context.res = {
// status defaults to 200 */
body: "Hello " + (req.query.name || req.body.name)
};
}
else {
context.res = {
status: 400,
body: "Please pass a name on the query string or in the request body"
};
}
context.done();
};
For configuration options in function.json, you can visit here and here.
For us this was fixed by removing this binding from function.json:
{
"type": "http",
"direction": "out",
"name": "res"
}
So the result is if you're running the function using a timingTrigger you'd have:
{
"scriptFile": "index.js",
"bindings": [
{
"name": "myTimer",
"type": "timerTrigger",
"direction": "in",
"schedule": "0 */1 * * * *"
}
]
}
If you move back to HTTP or other you need to fill out the bindings in full again and remove the reference to the timer trigger:
{
"scriptFile": "index.js",
"bindings": [
{
"authLevel": "function",
"type": "httpTrigger",
"direction": "in",
"name": "req",
"methods": [
"get",
"post"
]
},
{
"type": "http",
"direction": "out",
"name": "res"
}
]
}
A packet contains the data below but I need to extract the following part:
"data":"YOeNkAAg1wQAYjm/pg==
using JavaScript in node-red. How i can do this?
{
"payload": "lora/01-01-01-01-01-01-01-01/39-31-37-33-5b-37-67-19/packet_sent
{
\"appeui\":\"01-01-01-01-01-01-01-01\",
\"codr\":\"4/5\",
\"data\":\"YOeNkAAg1wQAYjm/pg==\",
\"datr\":\"SF7BW125\",
\"deveui\":\"39-31-37-33-5b-37-67-19\",
\"freq\":868.29999999999995,
\"gweui\":\"00-80-00-00-a0-00-24-6d\",
\"id\":0,
\"ipol\":true,
\"mhdr\":\"60e78d900020d704\",
\"mic\":\"6239bfa6\",
\"modu\":\"LORA\",
\"ncrc\":true,
\"opts\":\"\",
\"port\":0,
\"powe\":11,
\"rfch\":0,
\"seqn\":1239,
\"size\":13,
\"tmst\":3491353235,
\"twnd\":1
}",
"fromip": "127.0.0.1:35068",
"ip": "127.0.0.1",
"port": 35068,
"_msgid": "193b00a8.e6c4ff"
}
var src = {
"payload": "lora/01-01-01-01-01-01-01-01/39-31-37-33-5b-37-67-19/packet_sent {\"appeui\":\"01-01-01-01-01-01-01-01\",\"codr\":\"4/5\",\"data\":\"YOeNkAAg1wQAYjm/pg==\",\"datr\":\"SF7BW125\",\"deveui\":\"39-31-37-33-5b-37-67-19\",\"freq\":868.29999999999995,\"gweui\":\"00-80-00-00-a0-00-24-6d\",\"id\":0,\"ipol\":true,\"mhdr\":\"60e78d900020d704\",\"mic\":\"6239bfa6\",\"modu\":\"LORA\",\"ncrc\":true,\"opts\":\"\",\"port\":0,\"powe\":11,\"rfch\":0,\"seqn\":1239,\"size\":13,\"tmst\":3491353235,\"twnd\":1}",
"fromip": "127.0.0.1:35068",
"ip": "127.0.0.1",
"port": 35068,
"_msgid": "193b00a8.e6c4ff"
}
var payload = src.payload;
payload = JSON.parse(payload.substr(payload.indexOf('{')));
console.log(payload.data);
console.log('"data":"' + payload.data + '"');
var finalResult = {};
finalResult.data = payload.data;
console.log(JSON.stringify(finalResult));
And after removing this strange part JSON could look like this
{
"payload": {
"appeui": "01-01-01-01-01-01-01-01",
"codr": "4/5",
"data": "YOeNkAAg1wQAYjm/pg==",
"datr": "SF7BW125",
"deveui": "39-31-37-33-5b-37-67-19",
"freq": 868.3,
"gweui": "00-80-00-00-a0-00-24-6d",
"id": 0,
"ipol": true,
"mhdr": "60e78d900020d704",
"mic": "6239bfa6",
"modu": "LORA",
"ncrc": true,
"opts": "",
"port": 0,
"powe": 11,
"rfch": 0,
"seqn": 1239,
"size": 13,
"tmst": 3491353235,
"twnd": 1
},
"fromip": "127.0.0.1:35068",
"ip": "127.0.0.1",
"port": 35068,
"_msgid": "193b00a8.e6c4ff"
}
If the resualt always look like data...== you can search in the payload for the content between data and == with
var res = array.payload.substring(
response.payload.lastIndexOf("data") + -1,
response.payload.lastIndexOf("==") + 3
);
var response = {
"payload": "lora/01-01-01-01-01-01-01-01/39-31-37-33-5b-37-67-19/packet_sent {\"appeui\":\"01-01-01-01-01-01-01-01\",\"codr\":\"4/5\",\"data\":\"YOeNkAAg1wQAYjm/pg==\",\"datr\":\"SF7BW125\",\"deveui\":\"39-31-37-33-5b-37-67-19\",\"freq\":868.29999999999995,\"gweui\":\"00-80-00-00-a0-00-24-6d\",\"id\":0,\"ipol\":true,\"mhdr\":\"60e78d900020d704\",\"mic\":\"6239bfa6\",\"modu\":\"LORA\",\"ncrc\":true,\"opts\":\"\",\"port\":0,\"powe\":11,\"rfch\":0,\"seqn\":1239,\"size\":13,\"tmst\":3491353235,\"twnd\":1}",
"fromip": "127.0.0.1:35068",
"ip": "127.0.0.1",
"port": 35068,
"_msgid": "193b00a8.e6c4ff"
}
var res = response.payload.substring(
response.payload.lastIndexOf("data") + -1,
response.payload.lastIndexOf("==") + 3
);
console.log(res)
I'm trying to use the Google Cloud Printing API. I previously had problems relating to the sending of my request. After some json/stringifying experimentation, I no longer get that error. Instead, my API calls are unsuccessful according to the response sent back by the Google API. Here's what I'm doing:
// Ticket used for google cloud printing
const ticket = {
"version":"1.0",
"print":{
"color":{"vendor_id":"psk:Color","type":0},
"duplex":{"type":0},
"page_orientation":{"type":0},
"copies":{"copies":1},
"dpi":{"horizontal_dpi":1200,"vertical_dpi":1200},
"media_size":{"width_microns":80000,"height_microns":58000,"is_continuous_feed":false},
"collate":{"collate":true},
"vendor_ticket_item":[
//Printer specific settings here, from the capabilities:
{"id":"psk:JobInputBin","value":"ns0000:Tray3"},
{"id":"psk:PageICMRenderingIntent","value":"psk:Photographs"},
{"id":"psk:PageMediaType","value":"ns0000:Auto"},
{"id":"psk:JobOutputBin","value":"ns0000:Auto"},
//etc.
]
}
}
request({
"method": "POST",
"content-type" : "application/json",
"url": googlePrintUrl + "submit",
"headers": {
"Authorization": "OAuth " + googleAccessToken
},
"body" : {
"printerid": "39875g133-ae7d-76hg-65af-jhe5bc682404",
"ticket": JSON.stringify(ticket),
"title": "TEST PRINT",
"content": "test msg",
"contentType": "text/plain"
},
"json": true
}, function (error, res, body){
if (error) {
console.log("There was an error with Google Cloud Print");
console.log(error);
return;
}
console.log("The server responded with:", body);
});
this request results in this response from the server:
The server responded with: { success: false,
request:
{ time: '0',
params: {},
user: 'mytest#gmail.com',
users: [ 'mytest#gmail.com' ] },
errorCode: 3,
message: 'Printer Id required for this request.' }
As you can see, the params field is empty. This is strange because when I use Postman to do the same request, this field is filled with the params I sent in the API call. Here's how I successfully did it in Postman:
Which generated the server response:
{
"success": true,
"request": {
"time": "0",
"params": {
"ticket": [
"{\"version\":\"1.0\",\"print\":{\"color\":{\"vendor_id\":\"psk:Color\",\"type\":0},\"duplex\":{\"type\":0},\"page_orientation\":{\"type\":0},\"copies\":{\"copies\":1},\"dpi\":{\"horizontal_dpi\":600,\"vertical_dpi\":600},\"media_size\":{\"width_microns\":80000,\"height_microns\":58000,\"is_continuous_feed\":false},\"collate\":{\"collate\":true},\"vendor_ticket_item\":[{\"id\":\"psk:JobInputBin\",\"value\":\"ns0000:Tray3\"},{\"id\":\"psk:PageICMRenderingIntent\",\"value\":\"psk:Photographs\"},{\"id\":\"psk:PageMediaType\",\"value\":\"ns0000:Auto\"},{\"id\":\"psk:JobOutputBin\",\"value\":\"ns0000:Auto\"}]}}"
],
"printerid": [
"39875g133-ae7d-76hg-65af-jhe5bc682404"
],
"title": [
"TEST"
],
"contentType": [
"text/plain"
],
"content": [
"**** test"
]
},
"user": "mytest#gmail.com",
"users": [
"mytest#gmail.com"
]
},
"xsrf_token": "AIp06DhAZRSLW9GlHWQLKykbpU-5fYRqcA:1531484990909",
"message": "Print job added.",
"job": {
"ticketUrl": "https://www.google.com/cloudprint/ticket?jobid\u003df11043fe-3e00-d912-11dd-c859718a5575",
"printerName": "",
"errorCode": "",
"updateTime": "1531484993830",
"title": "**** TEST",
"message": "",
"ownerId": "mytest#gmail.com",
"tags": [
"^own"
],
"uiState": {
"summary": "QUEUED",
"progress": "Delivery attempts: 1"
},
"numberOfPages": 1,
"createTime": "1531484991068",
"semanticState": {
"delivery_attempts": 1,
"state": {
"type": "QUEUED"
},
"version": "1.0"
},
"printerid": "39875g133-ae7d-76hg-65af-jhe5bc682404",
"fileUrl": "https://www.google.com/cloudprint/download?id\u003df11043fe-3e00-d912-11dd-c859718a5575",
"id": "f11043fe-3e00-d912-11dd-c859718a5575",
"rasterUrl": "https://www.google.com/cloudprint/download?id\u003df11043fe-3e00-d912-11dd-c859718a5575\u0026forcepwg\u003d1",
"contentType": "application/pdf",
"status": "QUEUED"
}
}
This is a successful printing job, and all the parameters sent by me are sent back in the response object.
So where am I going wrong in my node.js code?
Postman sends payload (printerid, content, title, etc) in formData rather than body
Underneath the "SEND" button is a button "Code" that can generate functional NodeJS (and other) snippets like
var request = require("request");
var options = { method: 'POST',
url: 'https://www.google.com/cloudprint/submit',
headers:
{ 'cache-control': 'no-cache',
Connection: 'keep-alive',
'Content-Length': '769',
'Accept-Encoding': 'gzip, deflate',
Host: 'www.google.com',
'Cache-Control': 'no-cache',
'Content-Type': 'application/json',
Authorization: 'Bearer ya29.GlxWB5_vr8QmJw3DChvVyqpRhNJ2hsuVzwNTJoYRH6r2VVGTwDE3MLNAN8pjTB3-BDWtZeIDrCDcP5DwYGywM1vgb9VMPhoi806HrMpOpKAaKzrgiliojec6IB2Cwg',
'content-type': 'multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW' },
formData:
{ printerid: 'd936d368-7ea4-6f66-84fd-6d5a7a357318',
title: 'Document Title',
content: 'Hello World',
ticket: '{"version":"1.0","print":{"vendor_ticket_item":[],"color":{"type":"STANDARD_MONOCHROME"},"copies":{"copies":1}}}',
contentType: 'text/plain' } };
request(options, function (error, response, body) {
if (error) throw new Error(error);
console.log(body);
});
AngularJS 1.6.6 has support for differentiation between XHR completion, error, abort, timeout, I have this code snippet which make a request to a url like below:
$http.get(url, {timeout: 1000})
.then(...)
.catch(function(error) {
console.log(error.xhrStatus) // could be abort, complete, error and timeout
});
When requesting my api takes more than 1 second the promise is rejected with xhrStatus of 'abort', I was wondering in what situation I will get 'timeout' and 'error' status texts?
Edit: It would be awesome if the answer provide the relevant server side code in Web Api
"timeout" will never occur as far as I can tell since the xhr in the $httpBackend never has a timeout property set instead angular uses it's own mechanism for aborting the xhr request if the timeout ms expires or the promise passed in resolves.
https://github.com/angular/angular.js/blob/master/src/ng/httpBackend.js#L165
"error" will occur if a request has been dispatched and the network connection has gone down
If a 500 or 200 comes back the status will be complete but angular will fire the success or error/catch handlers on the http promise depending on the status code.
Test result model (note I disconnected the network to get the result for test3.php, the test.html page loaded, then I disconnected the network before the setTimeout fired the get hence forcing the xhr.status to error)
{
"msg1": {
"data": {
"val": "test"
},
"status": 200,
"config": {
"method": "GET",
"transformRequest": [
null
],
"transformResponse": [
null
],
"jsonpCallbackParam": "callback",
"timeout": 1000,
"url": "test1.php",
"headers": {
"Accept": "application/json, text/plain, */*"
}
},
"statusText": "OK",
"xhrStatus": "complete"
},
"msg2": {
"data": null,
"status": -1,
"config": {
"method": "GET",
"transformRequest": [
null
],
"transformResponse": [
null
],
"jsonpCallbackParam": "callback",
"timeout": 1,
"url": "test2.php",
"headers": {
"Accept": "application/json, text/plain, */*"
}
},
"statusText": "",
"xhrStatus": "abort"
},
"msg3": {
"data": null,
"status": -1,
"config": {
"method": "GET",
"transformRequest": [
null
],
"transformResponse": [
null
],
"jsonpCallbackParam": "callback",
"url": "test3.php",
"headers": {
"Accept": "application/json, text/plain, */*"
}
},
"statusText": "",
"xhrStatus": "error"
},
"msg4": {
"data": "",
"status": 500,
"config": {
"method": "GET",
"transformRequest": [
null
],
"transformResponse": [
null
],
"jsonpCallbackParam": "callback",
"url": "test4.php",
"headers": {
"Accept": "application/json, text/plain, */*"
}
},
"statusText": "Internal Server Error",
"xhrStatus": "complete"
}
}
Test.html
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.6/angular.js"></script>
<script>
angular.module('myApp', [])
.controller('MyCtrl', function($http){
var url1 = "test1.php";
var url2 = "test2.php";
var url3 = "test3.php";
var url4 = "test4.php";
var ctrl = this;
ctrl.model={msg1:null, msg2:null, msg3:null, msg4:null}
$http.get(url1, {timeout: 1000})
.then(function(resp){
ctrl.model.msg1 = resp
})
.catch(function(error) {
ctrl.model.msg1 = error;
});
$http.get(url2, {timeout: 1})
.then(function(resp){
ctrl.model.msg2 = resp
})
.catch(function(error) {
ctrl.model.msg2 = error;
});
setTimeout(function(){
$http.get(url3)
.then(function(resp){
ctrl.model.msg3 = resp
})
.catch(function(error) {
ctrl.model.msg3 = error;
});
}, 2000);
$http.get(url4)
.then(function(resp){
ctrl.model.msg4 = resp
})
.catch(function(error) {
ctrl.model.msg4 = error;
});
});
</script>
</head>
<body ng-app="myApp" ng-controller="MyCtrl as myCtrl">
<pre>{{myCtrl.model|json}}</pre>
</body>
</html>
test1.php
<?php
echo "{\"val\":\"test\"}";
test2.php
<?php
sleep(10);
test3.php
<?php
sleep(1000);
test4.php
<?php
throw new Exception("Error");
this is my json response
{
"sessid": "some_value",
"session_name": "some_vvalue",
"token": "some_vvalue",
"user": {
"uid": "12125",
"name": "some_vvalue",
"mail": "some_vvalue",
"theme": "",
"signature": "",
"signature_format": "filtered_html",
"created": "1486476553",
"access": "1489577945",
"login": 1489585116,
"status": "1",
"timezone": "Asia/Kolkata",
"language": "",
"picture": "0",
"data": false,
"roles": {
"2": "authenticated user"
},
"rdf_mapping": {
"rdftype": ["sioc:UserAccount"],
"name": {
"predicates": ["foaf:name"]
},
"homepage": {
"predicates": ["foaf:page"],
"type": "rel"
}
}
}
}
i just want to get first three values that is session_name,session_id and token, And i am getting this value during post request,here is my code for parsing.
async onPressLogin() {
try {
loaderHandler.showLoader("Please wait!!!");
let response = await fetch(
'http://some_url/api/user/login', {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
'X-CSRF-Token': this.state.token,
},
body: JSON.stringify({
username: this.state.name,
password: this.state.password,
})
});
let responseText = await response.text();
let responseJson = await response.json();
if (response.status >= 200 && response.status < 300){
await AsyncStorage.setItem(SESSION_TOKEN, responseJson.token);
await AsyncStorage.setItem(SESSION_NAME,responseJson.session_name);
await AsyncStorage.setItem(SESSION_ID,responseJson.sessid);
Alert.alert('Store Token', 'Session Token'+responseJson.token)
/// Alert.alert('Server response', responseJson)
loaderHandler.hideLoader();
Actions.Documents();
}
else {
loaderHandler.hideLoader();
let error = responseText;
Alert.alert('Login', error)
}
} catch(errors) {
loaderHandler.hideLoader();
Alert.alert('Login_server', errors)
loaderHandler.hideLoader();
}
}
I am trying to store these three values in async storage for further use. Please help me tried everything but could not solve the error. Let me know if you will need any other code. Thanks
This is the error which i am getting
TypeError: expected dynamic type'string',but had type'object'