Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations gkittelson on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

HTTP request GET files

Status
Not open for further replies.

AlastairP

Technical User
Feb 8, 2011
286
AU
I am setting up a REST server in node.js, the client is a windows tablet running VFP9

I am struggling with downloading files.
That's ok for text & strings and so far a zip file - seems ok. But not for images.

I send a request to the server for a file by name, server responds with "I got file"
I then send a GET request to download the file. The file is returned as a data string in the response. I guess that is how it's done?
Can not the file be attached to the response as an object? Or does the contents of the file need to be sent in a different format server side?

I have tried setting the headers in the GET request for 'Content-Type' to 'image/jpeg'. That made no difference.

I have tried FILETOSTR and FRWITE with no luck, image is not able to be opened.



Alastair
 
Alastair,

Downloading an image should not be different to download a zip file. If you've successfully downloaded a zip file, getting an image would be as simple.

Is that a public service that we can try for ourselves? Can you post the code of your last attempt?
 
FRWITE surely isn't going to work... B-) (Typo)

Regards

Griff
Keep [Smile]ing

There are 10 kinds of people in the world, those who understand binary and those who don't.

I'm trying to cut down on the use of shrieks (exclamation marks), I'm told they are !good for you.
 
Alastair, when you say you have "tried FILETOSTR and FRWITE with no luck", what exactly happens? Do those commands give an error, or what?

In any case, all that FILETOSTR() and FREAD() -(not FRWRITE(), as Griff correctly pointed out) - can do is to copy theedata into a memory variable. There is no point in doing that if the data is that of an image. You won't be able to use the data in any useufl way. You'll need some program or function that can actually work with images.

If the image is a BMP, ICO or WMF (or possibly some other types), you can get an object reference to it with LOADPICTURE(), but even that probably won't help very much.

Mike

__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips and downloads
 
Hi Mike

I can successfully send text strings & json both ways between server and client. This is straightforward. Files seem a bit different.

When the server sends a zip file, I use STRTOFILE client side to make the ZIP file from the ResponseText.
However I did not investigate the validity of the data contained within the ZIP, just saw that it contained the files.

I wonder if I am missing some basic understanding of how this works: is there a different approach when it comes to sending files server side?

In all the information I have been able to find, there is plenty of examples server side and I have tried a number of different ways to send the data from the server.
On the server side I can write a header called 'Attachment' with the name of the file,
so on the client side I could write a DO CASE statement to deal with the different file types being transferred.

So with image files STRTOFILE is no good, the resulting file can't be read.



Client side (VFP9)
Code:
LOCAL ServerRequest AS WinHttp.WinHttpRequest
oServerRequest = CREATEOBJECT("WinHttp.WinHttpRequest.5.1")


lcImageheader = 'image/jpeg'


TRY 
	oServerRequest.Open("GET",'[URL unfurl="true"]http://localhost:3001/UPDATES_WIN/TESTIMAGE.JPG',[/URL] .f.)
	oServerRequest.SetRequestHeader('Content-Type',lcImageheader) 
	oServerRequest.Send()
	
	lcValidate = this.response_validate(oServerRequest) && validates the response code returned

        this.response_statuscode=oServerRequest.status
        this.response_text=oServerRequest.ResponseText
        this.response_statustext=oServerRequest.statustext
		
CATCH 
	lcValidate =.f.
ENDTRY 	
lcResponseText = this.response_text  

SET SAFETY OFF 
IF FILE(lcDestinationfile)
	DELETE FILE (lcDestinationfile)
ENDIF 		
lnByts = STRTOFILE(lcResponseText,lcDestinationfile,0)


RETURN lcValidate

Server side: (Nodejs)
Code:
const express = require('express');
const router = express.Router();
const checkAuth = require('../middleware/check-auth');
const fs = require("fs");

const filePath = process.env.updates_win;


// Get updates for windows tablet
router.get('/:payloadName',checkAuth,(req, res, next) => {
    const payloadName = req.params.payloadName; // the name of the file we are looking for
 
    fs.access(filePath + payloadName, error => {
        if (!error) {
            res.contentType('image/jpeg');
            res.sendFile(filePath + payloadName);    
            // send file
            
        } else {
            // The check failed
            res.status(400).json({
                message: "File Not Found"
            });
        }
    });
});
   
module.exports = router;
 
Alastair,

You're not doing anything with the validation, if it fails you're still trying to create the file.

But that is not the key point: to retrieve binary data from a Web Server, use ResponseBody instead, not ResponseText. ResponseBody returns raw data from the call. Once retrieved, STRTOFILE() will work ok with any kind of content, including images.

A final point: no need to set the request header to image/file. You're not uploading any content.
 
So what dues this do?

Code:
this.response_validate(oServerRequest)

Does it wait for the response at all?

More broadly asked, what is "this". With the methods and properties it has, like .response_statuscode and .response_text, it seems to handle HTTP requests. And if it does so by using WinHttp.WinHttpRequest.5., then what are you actually doing here? Modifying class code, what method is this? Is it the classes' HTTP request method? Then use it, don't modify it. You're not using this class, you're redefining it.

Besides, you don't set that you want an image/jpeg returned with a content-type header of the request. Indeed you tell what your request body is. And you don't send an image. In the simplest case, the server will just ignore that.

When you want to indicate what you accept as a response you tell that in an Accept header.

See:

Bye, Olaf.

Olaf Doschke Software Engineering
 
Also, as you don't know whether receiving or sending fails. Simply try each half:

1. Try your VFP client code with any other image form anywhere else, another URL, like or any other image
2. Try to get your image displayed by a browser with a little HTML like:

Code:
<html><body><img src='[URL unfurl="true"]http://localhost:3001/UPDATES_WIN/TESTIMAGE.JPG'></body></html>[/URL]

Bye, Olaf.


Olaf Doschke Software Engineering
 
Either you're busy or you solved it already. Just a final note: A request like is a simple GET request and usually needs no script to run to respond with the file, this is something a webserver can do without running any code. It's a very direct request. Node works different, it does not run within a webserver, the app you define in a main js script IS the webserver, but anyway there's a package http-server which makes it simply starting that with the directory as parameter.


Bye, Olaf.

Olaf Doschke Software Engineering
 
Hi Olaf,
Yes I have been busy.

"this.response_validate(oServerRequest)" is a method that validates the response code

I have got image transfers to work, thanks to atlopes direction to extract the data from the ResponseBody, not the ResponseText.

Alastair
 
OK, Alistair,

as the overall problem of the VFP side mainly was solved using ResponseBody instead of ResponseText it now it becomes less important to know what "THIS" is in the context, but you could perhaps enlighten future readers of this thread what library you're using here or if it's your own class definition.

You're doing an async transfer (because last parameter of oServerRequest.Open() call is .f.) so there will be a response and response status, that's surely not the problem, but I continue to wonder what such an extra response_validate method would do other than checking the status code is 200 (OK). Besides, when you have a class concerned about a HTTP request, I'd expect it to have a property oServerRequest instead of a local variable it passes on to other methods. All such details point out poor class design. Sorry to say so.



Next up: I assume the other side is working, too, then. It still seems overcomplicated to me, but I see similar code suggested to let the express framework act as "file server", for example here:

Then there is nodes own howto on this with native base modules (
Code:
var fs = require('fs'),
    http = require('http');

http.createServer(function (req, res) {
  fs.readFile(__dirname + req.url, function (err,data) {
    if (err) {
      res.writeHead(404);
      res.end(JSON.stringify(err));
      return;
    }
    res.writeHead(200);
    res.end(data);
  });
}).listen(3001);

And finally, it can be done much simpler with express, too (
Code:
var express = require('express'),
app = express(),
port = process.env.PORT || 3001;

app.use(express.static(__dirname + '/public'));
app.listen(port);

As already said all this is a no brainer in the usual web servers used like IIS or apache or nginx. You just set up a root directory and any GET request to a file is automatically responded to with the file including the correct mime type header. And there's more to it also in terms of handling permissions and authentication, which seems to be an aspect of your script, too.

When you want to go the node.js route, you should handle more than this core aspect, too, though, and the classic webservers have major advantages. You can combine it and here's a blog article of Scott Hanselman highlighting some important points about why to embed node inside IIS or another web server and not use it directly:


Last, not least: your code looks at req.params.payloadName. As far as I understand it this means your request to a file would need to be a POST request having a parameter of the file requested in its request body. As it seems to work I might have this wrong, but certainly there are easier ways, even if you insist on using express for extended use of express overall in the bigger picture.

Bye, Olaf.

Olaf Doschke Software Engineering
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top