In my application I create a file on the backend, and I wish then to deliver that to the user via a browser download. I have tried numerous
Here is the express backend:
app.get('/download', (req, res) => {
res.download('filename.txt', function (err) {
console.log(err);
});
})
The console call isn't returning, so presumably no error. Here is what I am doing in the front-end, following advice here and here:
window.open('localhost:3000/download');
The result is that I get a blank window popping up, but no download. I have also tried this:
const filePath = 'localhost:3000/download/';
const link = document.createElement('a');
link.href = filePath;
link.download = filePath.substr(filePath.lastIndexOf('/') + 1);
link.click();
But in this case, nothing happens.
What am i doing wrong? I at a loss even how to debug any further.
Update 1
Thanks #jal_a, I've made progress. I realise now that if I manually create a window and enter the url (as suggested) the download works. However, when the window is launched from the application using window.open(url) where url is the same, the window opens but the download doesn't initiate. If I then go to the created window, click in the url and press return ... voila! It works! How can I make the download initiate from the application launched window?
Update 2
Thanks #IceMetalPunk, I tried that and I'm getting the following error in the console - the file I'm trying to download is gps data in gpx format - which I can see in the response, but it seems to be expecting JSON?? Do I need to do any pre-processing to send a file?:
HttpErrorResponse {headers: HttpHeaders, status: 200, statusText: "OK",
url: "http://localhost:3000/download/", ok: false, …}
error:
error: SyntaxError: Unexpected token < in JSON at position 0 at JSON.parse
...
text: "<?xml version="1.0" encoding="UTF-8"?>
↵<gpx version="1.1" xmlns="http://www.topografix.com/GPX/1/0">
↵ <rte>
↵ <name>undefined</name>
↵ <rtept lat="50.70373" lon="-3.07241" />
↵ <rtept lat="50.70348" lon="-3.07237" />
↵ </rte>
↵</gpx>"
__proto__: Object
headers: HttpHeaders {normalizedNames: Map(0), lazyUpdate: null, lazyInit:
ƒ}
message: "Http failure during parsing for http://localhost:3000/download/"
name: "HttpErrorResponse"
ok: false
status: 200
statusText: "OK"
url: "http://localhost:3000/download/"
__proto__: HttpResponseBase
The issue was that my download link did not include the http:// element of the url, as this answer describes.
Related
While uploading pictures using the Imgur API,
some pictures are not uploaded and
returns status 400 or 417 errors.
{
status: 400,
success: false,
data: {
error: "We don't support that file type!",
request: '/3/upload'
}
{
status: 417,
success: false,
data: {
error: 'Internal expectation failed',
request: '/3/upload',
method: 'POST'
}
}
This error was fixed upon launching the console.
But every time I upload a picture I have to restart the console. How may I prevent this from happening?
The 417 error states that the Imgur CDN was expecting a file type such as .png, .mp4, .gif, etc. You may view the supported file types here.
The 400 indicates an improper / bad request , while requesting the API for a POST type request you must know how to properly request it, you may refer to the proper method here.
Note: Your "Account" and your "Application" are distinct entities.
If you try to upload to an album on your account, thinking your application has access rights to it because they are tied to the same email, you'll probably get the 417 error.
Also, it seems that imgur validates the .PNG file before validating access rights.
I have concluded that as you are trouble shooting , this is a rough gauge of "how close to succcess" you are:
1: VERY CLOSE :
"Internal Expectation Failed"
Your .PNG payload within the form-data is probably correct.
2: COLDER :
"We Don't Support That File Type"
You probably corrupted your .PNG binary file when attempting to concat it into the "form-data" payload.
3: COLDEST :
"bad request"
You really fucked up bad.
If you are rolling your own "multi-part form-data" like I did, one of the posters here has a good low-level example that does NOT use 3rd party libraries:
NodeJS Request how to send multipart/form-data POST request
Your payload is constructed something like this:
payload=Buffer.concat([
Buffer.from( formdata_string_top , "utf8" )
, Buffer.from( png_binary_file , "binary" )
, Buffer.from( final_formdata_boundary, "utf8" )
]);;
You might be tempted to do this , because it is readable in your
logs, but it WILL_CORRUPT_YOUR_BINARY_FILE
payload=Buffer.concat([
Buffer.from( formdata_string_top , "utf8" )
, Buffer.from( png_binary_file , "binary" )
, Buffer.from( final_formdata_boundary, "utf8" )
]).toString( "utf8" );
I am getting this error, it points to client.js line 21. It is the second .then of the fetch(create.php).
The first response returns 200. So, not sure how to fix it. The whole code so far is as extracted from demo instructions. https://stripe.com/docs/payments/integration-builder
See browser console info:
jquery-migrate.min.js?ver=3.3.2:2 JQMIGRATE: Migrate is installed, version 3.3.2
?ver=3.0.0:1 You may test your Stripe.js integration over HTTP. However, live Stripe.js integrations must use HTTPS.
value # ?ver=3.0.0:1
Ec # ?ver=3.0.0:1
Sc # ?ver=3.0.0:1
(anonymous) # client.js:3
client.js:18 Response {type: "basic", url: "http://amore-paraiso.local/wp-content/plugins/sm-amore-stripe/create.php", redirected: false, status: 200, ok: true, …}body: (...)bodyUsed: trueheaders: Headers {}ok: trueredirected: falsestatus: 200statusText: "OK"type: "basic"url: "http://amore-paraiso.local/wp-content/plugins/sm-amore-stripe/create.php"__proto__: Response
content-tss.js:1 TSS: content-tss.js loaded: https://js.stripe.com/v3/m-outer-59cdd15d8db95826a41100f00b589171.html#url=http%3A%2F%2Famore-paraiso.local%2Fexperiences%2Fbride-groom%2F%3F&title=Bride%20%26%20Groom%20%E2%80%93%20Amore%20Paraiso&referrer=http%3A%2F%2Famore-paraiso.local%2Fexperiences%2Fbride-groom%2F%3F&muid=bb6c8b5b-6e39-4451-91e7-10092d15ec8824d547&sid=3aa75c2f-71f2-493c-ae1b-8f76050ebb800df509&version=6&preview=false
content-ads.js:1 INS: content-ads.js loaded: https://js.stripe.com/v3/m-outer-59cdd15d8db95826a41100f00b589171.html#url=http%3A%2F%2Famore-paraiso.local%2Fexperiences%2Fbride-groom%2F%3F&title=Bride%20%26%20Groom%20%E2%80%93%20Amore%20Paraiso&referrer=http%3A%2F%2Famore-paraiso.local%2Fexperiences%2Fbride-groom%2F%3F&muid=bb6c8b5b-6e39-4451-91e7-10092d15ec8824d547&sid=3aa75c2f-71f2-493c-ae1b-8f76050ebb800df509&version=6&preview=false
VM353:4 hosted page injected
(index):1 Uncaught (in promise) SyntaxError: Unexpected token < in JSON at position 0
Promise.then (async)
(anonymous) # client.js:21
content-tss.js:1 TSS: content-tss.js loaded: https://m.stripe.network/inner.html#url=http%3A%2F%2Famore-paraiso.local%2Fexperiences%2Fbride-groom%2F%3F&title=Bride%20%26%20Groom%20%E2%80%93%20Amore%20Paraiso&referrer=http%3A%2F%2Famore-paraiso.local%2Fexperiences%2Fbride-groom%2F%3F&muid=bb6c8b5b-6e39-4451-91e7-10092d15ec8824d547&sid=3aa75c2f-71f2-493c-ae1b-8f76050ebb800df509&version=6&preview=false
content-ads.js:1 INS: content-ads.js loaded: https://m.stripe.network/inner.html#url=http%3A%2F%2Famore-paraiso.local%2Fexperiences%2Fbride-groom%2F%3F&title=Bride%20%26%20Groom%20%E2%80%93%20Amore%20Paraiso&referrer=http%3A%2F%2Famore-paraiso.local%2Fexperiences%2Fbride-groom%2F%3F&muid=bb6c8b5b-6e39-4451-91e7-10092d15ec8824d547&sid=3aa75c2f-71f2-493c-ae1b-8f76050ebb800df509&version=6&preview=false
Most likely scenario is that your create.php is encountering an error and returning an error page as HTML (hence the < at position 0). You need to debug your create.php to understand where it is failing, then correct that. Check your Stripe developer logs to see if the API request is made successfully.
I've had simular problems passing data from php to js. Instead of immediately parsing the data, just do console.log(this.responseText) ; and it will show you the content. Normally it's an error in your php code and it will tell you where the error is and what's causing it for you to fix
I've encountered this error a few times.
You aren't actually getting back JSON as a response, and so the attempt to parse that response as JSON is failing.
If you are doing something like result.json() you can instead log result.text() and have a look at what is actually being returned.
PHP has a habit of catching people out and returning HTML rather than JSON.
Here is a massively popular Stack Overflow thread on the topic:
SyntaxError: Unexpected token < in JSON at position 0
Edit because reviewed:
Your error is appearing here
.then(function(result) {
return result.json();
})
So if you want to make sure this is JSON you can check the response content type like below. Taken from MDN
fetch("/create-payment-intent", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(purchase)
})
.then(result => {
const contentType = result.headers.get('content-type');
if (!contentType || !contentType.includes('application/json')) {
// Or do something else with the result to get it into JSON
throw new TypeError("Oops, we haven't got JSON!");
}
return result.json();
}
It turned out the error was on the require './stripe-php/init.php'; on the create.php file.
As I am developing it with Wordpress I had it as require plugin_dir_url(__FILE__) . 'stripe-php/init.php';.
Summary:
Make sure the path to require stripe-php/init.php is correct, as below:
require './stripe-php/init.php';
Thanks to #jason who recommended checking the Network tab.
In a previous Laravel 7 project I used XMLHttpRequest() to upload a file with progress bar successfully. Now, in a forked project where I need this similar code, the XMLHttpRequest always returns the response as null. What is going wrong?
Here is the upload.js part:
function upload(params...){
var data = new FormData();
var request = new XMLHttpRequest();
request.responseType = "json";
request.onload = function() {
console.log(`Loaded: ${request.status} ${request.response}`);//request.response IS ALWAYS NULL but the status is 200, statusText = 'OK' and readyState = 4.
};
request.open("post",url);
request.send(data);
}
Here is the corresponding uploadController.php who sends back the response:
if($fileUploaded){
return response()->json(
[
'message'=>'File uploaded successfully 👍🏽',
'filename'=>$fileUploaded,
]
);
}
Notes:
The file is uploaded correctly and registered in the database.
If I change request.responseType = "json"; to whatever else, the response is no longer null, but I get it in XML format!
Why do I get request.response as null?
This is the response:
XMLHttpRequest { onreadystatechange: null, readyState: 4, timeout: 0, withCredentials: false, upload: XMLHttpRequestUpload, responseURL: "http://myApp.local/upload", status: 200, statusText: "OK", responseType: "json", response: null }
If I inspect the network, the uploadController.php does get the json response. However, from the javascript side, it's null. Why? Can anyone shed some light?
Solved
Guys, thank you. My bad... I'd forgotten some var_dump()s left behind in my code, which were causing the request.response to be null.
Man, have you already checked whether your backend is printing information?
Maybe you've forgotten to comment a dd() or var_dump() function.
Use the "inspect element" tool of your favorite browser. Right at the "network" tab, check the response. There might be some extra text coming right from a var_dump or something like that.
I am building the API with Swagger and NodeJS, the annoying problem I have faced so far is Swagger validates the response, and it's not always smooth.
My case:
In file .yaml: I checked the yaml syntax with Swagger Editor => File Yaml is correct.
/user/createNew:
x-swagger-router-controller: xxxxxxx
post:
tags:
- User
summary: Create New User
# used as the method name of the controller
operationId: createNewUser
parameters:
- name: NewUserReq
in: body
required: true
description: Email register
schema:
$ref: "#/definitions/NewUserReq"
responses:
"201":
description: Successful
schema:
# a pointer to a definition
$ref: "#/definitions/CreateUserResp"
# responses may fall through to errors
default:
description: Error
schema:
$ref: "#/definitions/ErrorResponse"
CreateUserResp:
properties:
status:
type: integer
description: Response status
response:
$ref: "#/definitions/MsgResponse"
MsgResponse:
required:
- resp_msg
properties:
resp_msg:
type: string
To check the response format, I generated the NodeJs file from Swagger Editor
examples['application/json'] = {
"response" : {
"resp_msg" : "aeiou"
},
"status" : 123
};
In controller file .js:
function createNewUser(req,res){
....
var resp = new Object();
resp.resp_msg=data.email;
final_response.status = 200;
final_response.response = resp;
console.log("createNewUser::Query succeffully", JSON.stringify(final_response));
//{"status":200,"response":{"resp_msg":"test#gmail.com"}}
res.set('Content-Type', 'application/json');
res.json(final_response);
}
Try to run API with Postman, the error happens with log below:
Error: Response validation failed: failed schema validation
at throwErrorWithCode (/var/app/current/node_modules/swagger-express-mw/node_modules/swagger-node-runner/node_modules/swagger-tools/lib/validators.js:121:13)
at Object.module.exports.validateAgainstSchema (/var/app/current/node_modules/swagger-express-mw/node_modules/swagger-node-runner/node_modules/swagger-tools/lib/validators.js:176:7)
at /var/app/current/node_modules/swagger-express-mw/node_modules/swagger-node-runner/node_modules/swagger-tools/middleware/swagger-validator.js:141:22
at /var/app/current/node_modules/swagger-express-mw/node_modules/swagger-node-runner/node_modules/swagger-tools/node_modules/async/lib/async.js:356:13
at async.forEachOf.async.eachOf (/var/app/current/node_modules/swagger-express-mw/node_modules/swagger-node-runner/node_modules/swagger-tools/node_modules/async/lib/async.js:233:13)
at _asyncMap (/var/app/current/node_modules/swagger-express-mw/node_modules/swagger-node-runner/node_modules/swagger-tools/node_modules/async/lib/async.js:355:9)
at Object.map (/var/app/current/node_modules/swagger-express-mw/node_modules/swagger-node-runner/node_modules/swagger-tools/node_modules/async/lib/async.js:337:20)
at validateValue (/var/app/current/node_modules/swagger-express-mw/node_modules/swagger-node-runner/node_modules/swagger-tools/middleware/swagger-validator.js:134:11)
at ServerResponse.res.end (/var/app/current/node_modules/swagger-express-mw/node_modules/swagger-node-runner/node_modules/swagger-tools/middleware/swagger-validator.js:252:9)
at ServerResponse.send (/var/app/current/node_modules/express/lib/response.js:205:10)
I cannot figure out what caused the error, I double checked the structure of JSON response.
Very appreciate for any suggestion.
You have put required: true which means you have to pass that parameter otherwise Response Validation Failed will appear.
I tried to reproduce but it gives me some errors. However, I tried removing MsgResponse and defining CreateUserResp as a single definition, and it worked:
CreateUserResp:
type: object
properties:
response:
type: object
properties:
resp_msg:
type: string
description: The response object
status:
type: number
description: The status code
It seems like you're not defining response as an object, and just adding some properties to it.
After trying some experiments, I made it work. My solution simply is changing response code "201" to "200" in yaml file, and it worked. I don't know why I left the response code "201". Anyway, I am still new with this, and don't know if it's a best practice or not. I am open to receive any better suggestion.
You can get this error if you don't specify in the header the data type sent within the request body
Content-Type : application/json
I'm at wits end trying to figure out how to get my API to return a valid JSON object.
I'm currently using the following code to send a response:
res.json({ foo: 'bar', secret: 'code' });
I have also tried:
res.setHeader('Content-Type', 'application/json');
res.send(JSON.stringify({ foo: 'bar', secret: 'code' }));
Both of the above methods work when I visit the API URL in browser. I get the expected:
{
"foo": "bar",
"secret": "code"
}
On the other hand, I'm having trouble parsing the JSON response from URL (the example below uses the request package from npm):
request({
url: API-URL,
json: true
}, function (error, response, body) {
if (!error) {
console.log(body);
} else {
console.log(error);
}
})
Using the above code, I get the following error response:
{
"code": "ENOTFOUND",
"errno": "ENOTFOUND",
"syscall": "getaddrinfo",
"hostname": <<Redacted>>,
"host": <<Redacted>>,
"port": 443
}
I've tried plugging in third-party API URLs and they work just fine (ie: Google Maps, and OpenWeatherAPI) so I'm pretty sure that I'm using request properly. I'm guessing there is a step I missed in setting up the API (or I'm doing something wrong)?
Testing my API URL in https://jsonformatter.curiousconcept.com/, the formatted JSON object shows up but I also get the following regardless of how I set the response header and encoding:
Error: Invalid encoding, expecting UTF-8, UTF-16 or UTF-32.[Code 29, Structure 0]
Any suggestions would be greatly appreciated!
Edit:
The above is in a live web app and Express works properly otherwise (everything else in the application works fine, the JSON response just isn't playing nicely with request or jQuery.