fetch() sends the wrong URL Request to server - javascript

I have encountered a strange problem, doing a POST request using fetch(). It should have been easy, but I keep having an error code 405 from the server. Furthermore, the request URL should be only "http://localhost:3000/api/teddies/order", but somehow the local Visual_liveserver keeps adding in front of the URL request (the local server is hosted on this with port 5500 : http://127.0.0.1:5500)... In the image below you can see the error code 405 and this strange request URL.
Network inspector of the POST method : fetch()
By following this link, you will be able to access the Git of this projet. Don't hesitate to have a look at it ;) The file that calls these functions is called "pageFillingPanier.js".
But in short find below the code of the function that has the fetch in it:
const sendPurchaseRequest = async function (dataToSend) {
console.log(dataToSend);
try {
let response = await fetch('h​ttp://localhost:3000/api/teddies/order', {
method: 'POST',
headers: {
'content-type': 'application/json'
},
body: JSON.stringify(dataToSend)
});
console.log(response.ok); //it shows false...
let responseData = await response.json();
sessionStorage.setItem('memoryResponse', responseData.orderId);
//window.location = 'remerciement.html';
} catch (error){
console.log(error);
}
}
Find below the code that calls the function:
document.getElementById('bttFormSend').addEventListener('click', function (e) {
e.preventDefault();
let formPurchaseOrder = {
contact : {
firstName : document.getElementById('firstName').value,
lastName : document.getElementById('lastName').value,
email : document.getElementById('email').value,
address : document.getElementById('adress').value,
city : document.getElementById('city').value},
products : []
};
for (let index = 0; index < basketToDisplay.length; index++) {
formPurchaseOrder.products.push(basketToDisplay[index].id);
}
//this function send the POST request to the server
sendPurchaseRequest (formPurchaseOrder);
});

As the image suggests, there's a non visible unicode character present in the url. This happens sometimes when you copy and paste the url from some other places.
%E2%80%8B in url encoded form and ​ without encoded.
Remove it and browser will recognize it as a valid url.
console.log(encodeURIComponent('h​ttp://localhost:3000/api/teddies/order'))
The url http://127.0.0.1:5500/ is added because browser doesn't detect the supplied url as a valid url hence consider it as a path and prepend your current url to it.

Related

Post method with lambda authorizer functional in postman but in front end gives 403 error

I am trying to post a slot through a form. Only people who specify correct access token can post a slot. But even when I enter the correct access token. It gives me error 403 and tells me I am "forbidden". When I test in post man the post method works. When testing in the front end it doesnt.
Error in console
CORS configuration
Javacript code to add slot
function addSlots() {
var response = "";
var jsonData = new Object();
jsonData.restaurant_name_date_time = document.getElementById("date_time_slot").value;
jsonData.number_of_pax = document.getElementById("number_of_pax_2").value;
jsonData.restaurant_name = document.getElementById("restaurant_name_slot").value;
// validate the access token
var access_token = document.getElementById("access_token").value;
console.log(jsonData.restaurant_name_date_time)
console.log(jsonData.number_of_pax)
console.log(jsonData.restaurant_name)
console.log(access_token)
var request = new XMLHttpRequest();
request.open("POST", "https://skdsdjakand.execute-api.us-east-1.amazonaws.com/slots", true);
request.setRequestHeader("Authorization", "Bearer " + access_token);
console.log(access_token)
request.onload = function () {
response = JSON.parse(request.responseText);
console.log(response)
if (response.message == "slot added") {
alert('Congrats! You have succesfully added a slot');
} else if (response.message == "forbidden") {
alert('Invalid token. Please enter a valid access token.');
} else {
alert('Error. Unable to add slot.');
}
};
request.send(JSON.stringify(jsonData));
}
Lambda Authorizer Code
import json
def lambda_handler(event, context):
if event['headers']['authorization'] == 'secretcode':
response = {
"isAuthorized": True,
"context": {
"anyotherparam": "values"
}
}
return response
else:
response = {
"isAuthorized": False,
"context": {
"anyotherparam": "values"
}
}
return response
API Gateway will not attempt to execute your handler lambda if the authorization header it was told to expect is not present in the request, and you'll get a forbidden response.
In your authorizer lambda, it looks like you're expecting the header with a lowercase leter "a" but you're sending a request with an uppercase letter "A". It may be case sensitive, so check that.
Other things to check:
Is the value you used for the identity source in the authorizer an exact match for the header that's being passed? Again, look for case mismatches.
Is your handler lambda even being invoked? There will be evidence of invocations in the Lambda monitor and/or CloudWatch logs. If it isn't, then API Gateway is stopping the response before it gets to your handler (probably due to an issue with the authorizer).
edit
I just noticed the value of the authorization header is "Bearer " + access_token but your authorizer is checking for the secret code without the Bearer prefix. You may have obfuscated that intentionally, but if that's the actual code then it'll never match.

How to change Python to Apps Script get api?

I want to change python to apps script in apps script have UrlFetchApp function i'm never use but i'm try
I have code python can get api normally
import requests
url = "https://api.aiforthai.in.th/ssense"
text = 'Have a good day'
params = {'text':text}
headers = {
'Apikey': "xxx-xxx-xxx"
}
response = requests.get(url, headers=headers, params=params)
print(response.json())
so now i'm try code apps script like this but notthing came out ;
Api dashboard call me i'm use api.
maybe wrong payload text?
Detail API
Host
https://api.aiforthai.in.th/ssense
Method
GET/POST
Header
Apikey : xxx-xxx-xxx
Content-Type : application/x-www-form-urlencoded
Parameter
text : text for analysis
This my wrong apps script code
function call_api() {
var url = "https://api.aiforthai.in.th/ssense"
var apiKey = "xxx-xxx-xxx";
var response = UrlFetchApp.fetch(
url,
{
"headers": {
"Apikey": apiKey,
"text": "Have a good day"
}
}
)
Logger.log(response)
}
Thank you for solution.
I believe your goal is as follows.
You want to convert the following python script to Google Apps Script.
import requests
url = "https://api.aiforthai.in.th/ssense"
text = 'Have a good day'
params = {'text':text}
headers = {
'Apikey': "xxx-xxx-xxx"
}
response = requests.get(url, headers=headers, params=params)
print(response.json())
You have already been confirmed that your python script worked fine.
When I saw your python script, text is sent as the query parameter. In this case, how about the folloiwng modification?
Modified script:
function call_api2() {
var text = "Have a good day";
var url = `https://api.aiforthai.in.th/ssense?text=${encodeURIComponent(text)}`;
var apiKey = "xxx-xxx-xxx";
var response = UrlFetchApp.fetch(
url,
{ "headers": { "Apikey": apiKey } }
);
Logger.log(response.getContentText());
}
Note:
If you test the above modified script, when an error occurs, please confirm your apiKey again.
If an error like status code 403 occurs, your URL might not be able to be requested from Google side. I'm worried about this.
Try this instead:
function call_api() {
var url = "https://api.aiforthai.in.th/ssense";
var apiKey = "xxx-xxx-xxx";
var response = UrlFetchApp.fetch(
url,
{
"method" : "GET",
"headers" : {
"Apikey" : apiKey,
"text" : "Have a good day"
}
}
);
Logger.log(response)
}
You can check out the UrlFetchApp documentation for future reference.

Authorization header in img src link

I have an api that uses jwt for authencation. I am using this api for a vuejs app. I am trying to display an image in the app using
<img src="my/api/link" />
But the api expects Authorization header with jwt token in it.
Can I add headers to browser request like this(Answer to few questions here has made me believe it's not possible)?
Is there any way around it(using js) or should i change the api itself?
You can not perform authentication on images which are directly used as href in img tag. If you really want this type of authentication on your images, then it's better to fetch them using ajax and then embed in your html.
By default browsers are sending cookies.
You can prevent cookie sending in fetch if you set header's {credentials: 'omit'}. MDN
Full fetch example:
const user = JSON.parse(localStorage.getItem('user'));
let headers = {};
if (user && user.token) {
headers = { 'Authorization': 'Bearer ' + user.token };
}
const requestOptions = {
method: 'GET',
headers: headers,
credentials: 'omit'
};
let req = await fetch(`${serverUrl}/api/v2/foo`, requestOptions);
if (req.ok === true) {
...
Now, when you are login in, in your website, the webapp could save
to credentials into both localStorage and cookie.
Example:
let reqJson = await req.json();
// response is: {token: 'string'}
//// login successful if there's a jwt token in the response
if (reqJson.token) {
// store user details and jwt token in local storage to keep user logged in between page refreshes
localStorage.setItem('user', JSON.stringify({token: reqJson.token}));
document.cookie = `token=${reqJson.token};`; //set the cookies for img, etc
}
So your webapp uses localStorage, just like your smartphone application.
Browser gets all the static contents (img, video, a href) by sending cookies by default.
On the server side, you can copy the cookie to authorization header, if there is none.
Node.js+express example:
.use(function(req, res, next) { //function setHeader
if(req.cookies && req.headers &&
!Object.prototype.hasOwnProperty.call(req.headers, 'authorization') &&
Object.prototype.hasOwnProperty.call(req.cookies, 'token') &&
req.cookies.token.length > 0
) {
//req.cookies has no hasOwnProperty function,
// likely created with Object.create(null)
req.headers.authorization = 'Bearer ' + req.cookies.token.slice(0, req.cookies.token.length);
}
next();
})
I hope it helps someone.
You can use a Service Worker to intercept the img fetchs and add the Authorization header with the JWT token before hitting the server. Described in:
https://www.sjoerdlangkemper.nl/2021/01/06/adding-headers-to-image-request-using-service-workers/
https://www.twelve21.io/how-to-access-images-securely-with-oauth-2-0/#:~:text=4.%20USE%20SERVICE%20WORKERS
A workaround I often use is by leveraging a so-called nonce API endpoint. When calling this endpoint from the authenticated client, a short living string (could be a guid) is generated (for instance 30 seconds) and returned. Server-side you could of course add current user data to the nonce if you wish.
The nonce is then added to the image's query string and be validated server-side. The cost of this workaround is an extra API call.The main purpose of the workaround however is an increased security warrantee. Works like a charm ;) .
This is my solution based on Tapas' answer and this question How to display Base64 images in HTML?:
let jwtHeader = {headers: { Authorization: "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpX..."}
let r = await axios.get(`/path/image`, {...jwtHeader, responseType:"arraybuffer"});
let d = Buffer.from(r.data).toString('base64');
let a = document.createElement('img');
a.src = `data:image/png;base64, ${d}`;
a.width = 300;
a.height = 300;
document.getElementById("divImage").appendChild(a);
In this case the html would have a <div id="divImage">
<img src="/api/images/yourimage.jpg?token=here-your-token">
In the backend you validate JWT from queryparam.
There is another one method adds headers to HTTP request. Is it "Intercept HTTP requests". https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Intercept_HTTP_requests
Try this
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>测试获取图片</title>
<script src="http://libs.baidu.com/jquery/2.0.0/jquery.min.js"></script>
</head>
<body>
<img id="test-img" src="" />
<script>
var request = new XMLHttpRequest();
request.open('GET','http://127.0.0.1/appApi/profile/cust/idcard/2021/12/30/533eed96-da1b-463b-b45d-7bdeab8256d5.jpg', true);
request.setRequestHeader('token', 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE2NDA5MTg1NTgsInVzZXJpZCI6IjMxIn0.TQmQE9E1xQwvVeAWRov858W2fqYpSMxZPCGlgvtcUDc');
request.responseType = 'arraybuffer';
request.onload = function(e) {
var data = new Uint8Array(this.response);
var raw = String.fromCharCode.apply(null, data);
var base64 = btoa(raw);
var src = "data:image;base64," + base64;
document.getElementById("test-img").src = src;
};
request.send();
</script>
</body>
</html>

JSON url parse returns NaN in Node.js

I have created a URL Shortener web service, which returns JSON, if correct parameters (url) is passed.
Now, since I am learning Node.js, I am trying to create a Node.js wrapper for parsing the data and printing them in console (for now).
I am using http and request module for parsing the JSON data which I received from the url response.
This is my code that prints the data :
var request = require('request');
var http = require('http');
var url = process.argv[2];
var apiUrl = "http://shtr.ml/stats-api.php?url=" + url;
http.get(apiUrl,function(res){
var body = '';
res.on('data',function(chunk)
{
body += chunk;
});
res.on('end',function(){
const resp = JSON.parse(body);
console.log(JSON.stringify(resp));
if(resp.message.toString() == "Success")
{
console.log("Short URL : ",resp.short-url);
console.log("Long URL : ",resp.long-url);
console.log("Creation Date : ",resp.created);
console.log("Total Clicks : ",resp.clicks);
}
else
{
console.log("Stats Error !!");
}
});
}).on('error',function(e){
console.log("Got an error ",e);
});
Now, following is my code output :
C:\node-shtr-module>node index.js http://shtr.ml/ZVFWdk
{"message":"Success","short-url":"http://shtr.ml/ZVFWdk","long-url":"https://github.com/beingadityak/dot-net-mysql","created":"2016-09-27 22:58:06","clicks":"21"}
Short URL : NaN
Long URL : NaN
Creation Date : 2016-09-27 22:58:06
Total Clicks : 21
Why is the resp.short-url returning NaN even though the JSON contains the URL ? Please help.
As always, thanks in advance.
access it using
resp['short-url'] and resp['long-url']

get html page as response from url inside an extension

I am developing an extension in which whatever request is coming i want to change the request parameters and send a dummy request to server to get response.
for eg. if original request loaded is www.abc.com/eg.php?user="some code", then i want to change it into www.abc.com/eg.php?user="ritubala" and get html page in the response for further processing inside my extension..
i used these codes given in following url
Return HTML content as a string, given URL. Javascript Function
but it is causing recursion...
so in short i want to get html code from a url inside my extension...plz do help
Use nsITraceableChannel, note that you get a copy of the content being loaded.
If you abort the request then it aborts giving you a copy.
Here's me using nsITraceableChannel: https://github.com/Noitidart/demo-nsITraceableChannel
What I think you want is this:
const { Ci, Cu, Cc, Cr } = require('chrome'); //const {interfaces: Ci, utils: Cu, classes: Cc, results: Cr } = Components;
Cu.import('resource://gre/modules/Services.jsm');
Cu.import('resource://gre/modules/devtools/Console.jsm');
var observers = {
'http-on-examine-response': {
observe: function (aSubject, aTopic, aData) {
console.info('http-on-modify-request: aSubject = ' + aSubject + ' | aTopic = ' + aTopic + ' | aData = ' + aData);
var httpChannel = subject.QueryInterface(Ci.nsIHttpChannel);
var requestUrl = httpChannel.URI.spec
if (requestUrl.indexOf('blah')) {
//httpChannel.cancel(Cr.NS_BINDING_ABORTED); //this is how you abort but if use redirectTo you don't need to abort the request
httpChannel.redirectTo(Services.io.newURI('http://www.anotherwebsite/', null, null));
}
},
reg: function () {
Services.obs.addObserver(observers['http-on-modify-request'], 'http-on-modify-request', false);
},
unreg: function () {
Services.obs.removeObserver(observers['http-on-modify-request'], 'http-on-modify-request');
}
}
};
//register all observers
for (var o in observers) {
observers[o].reg();
}
note the redirectTo function is for FF20+
https://developer.mozilla.org/en-US/docs/XPCOM_Interface_Reference/nsIHttpChannel#redirectTo%28%29
so combine this example with the nsITraceableChannel demo and you'll have what you want.
if you don't want to redirect you can abort the request, get the DOCUMENT of the request and then xmlhttprequest the new page which gives you the source FIRST and doesnt load it to tab, and then modify the source then load it back to the DOCUMENT.
OR instead of xmlhttprequesting it, just abort the request, redirectTo the new page and then modify the tab. to get the tab of the channel see solution here:
Security Error when trying to load content from resource in a Firefox Addon (SDK)
also to do http requests from an extension see this snippet: https://gist.github.com/Noitidart/9088113

Categories

Resources