- Home /
Using WWW to simply post a slab of text .. ala JSON
Normally I use WWW and AddField to simply create forms to post, essentially like
POST /page/page
name="steve"
height="181"
however, if you just want to do this for typical modern web services:
POST /page/page
I will take care of
all this myself
just let me pass you the text, pls Unity
there's actually NO WAY to do that, right???
An intelligent colleague suggested this:
byte[] dd = Encoding.ASCII.GetBytes(stuff.ToCharArray());
WebRequest request = new WebRequest();
request.www = new WWW(happyURL, dd);
but I have Fear. Does anyone have any suggestions on this? Thank you!
Answer by Bunny83 · Apr 22, 2013 at 08:02 PM
You don't have to use key-value pairs as post data. Post data can be any data which is simply appended on the request headers. On the server side it's up to you to parse the incoming data properly. PHP for example will parse key-value pairs automatically into an associative array.
An HTTP request is actually very simple. It may consists of 3 major parts:
The actual request which just contains the method, the path of the requested resource and the used protocol
A list of optional header fields
Optional post-data
The HTTP header (which consists of the first request line and all header fields) is finished by an empty line. Everything that follows the second CR / LF pair is post data.
The general layout:
GET /path/to/resource HTTP/1.1
Header-Field-Name: Value
Header-Field-Name: Value
Post data .......
All the way until the transfer is aborted
Unity's WWW class allows you to define almost everything "manually".
Let's take a look at the actual WWW constructor, all others are just using this one:
new WWW(URL, postData, requestHeaders);
Those are:
URL = a complete URL. The domain part is used to determine the IP to which server the request should be sent. The path information goes into the first request line
postData = arbitrary data which is simply appended at the end. The WWW class uses this to determine whether to use "GET" or "POST". If the post data is "null" it will perform a GET if it's set to an byte array it will send a POST request.
requestHeaders = a Hashtable which contains the desired HTTP request headers.
Here are the two limitations of the WWW class:
You can't append any post data on a GET request. It actually doesn't make much sense since all HTTP servers will ignore it, but technically it's a limitation.
You can only add each HTTP header once. This is actually against the HTTP standard. This limitation comes from the fact that Unity uses a Hashtable for storing the headers. A hashtable can't have two or more identical keys.
The WWWForm class is just a helper class to create the post data and the request headers for a "Web form" but it's only useful when you want to send url-encoded data. The headers generated by WWWForm are, well, very simple:
public Hashtable headers
{
get
{
Hashtable hashtable = new Hashtable();
if (this.containsFiles)
{
hashtable["Content-Type"] = "multipart/form-data; boundary=\"" + Encoding.UTF8.GetString(this.boundary) + "\"";
}
else
{
hashtable["Content-Type"] = "application/x-www-form-urlencoded";
}
return hashtable;
}
}
This is all. The WWWForm just selects the correct Content-Type depending on if you added binary form data or not. But again you don't have to use WWWForm and you don't have to use url-encoded data.
So here's an example how to send a fully customized POST request:
//C#
string ourPostData = "{\"someJSON\":42}";
Hashtable headers = new Hashtable();
headers.Add("Content-Type", "application/json");
headers.Add("Cookie", "Our session cookie");
byte[] pData = Encoding.ASCII.GetBytes(ourPostData.ToCharArray());
WWW www = new WWW("http://our.server.domain.name/path/to/our/resource/file", pData, headers);
This would produce a request like this:
POST /path/to/our/resource/file HTTP/1.1
Content-Type: application/json
Cookie: Our session cookie
{"someJSON":42}
I'm not sure if Unity will add an "Content-Length" header automatically when you add post data, but usually a Content-Length header must be included when you post and additional data since the server doesn't know how much data will follow. It usually just waits until the connection is closed, but it's better to tell the server how much data he has to expect.
Btw to read the posted data in PHP see this SO question.
It's actually quite shocking that ~90% of the PHP users think post data always have to be url encoded data. Unfortunately there's very little information on raw post data.
A RESTful communication just follows some rules. For example that the communication is stateless on the server side. So all data required to precess the request have to be transmitted by the client, each request.
Ajax is just a name for the technique to "manually" executing sub-requests from a loaded webpage and process the results on the client side. From HTTP view it's just another request ;)
Your example of Content-Length looks right, however as i said i'm not sure if Unity add this field "automatically". I would have to try this with WireShark to see if it's added.
Thanks for all the upvotes, but don't forget the question ;)
Do you want a GET or POST request? Because Unity deter$$anonymous$$es which one it should use on the fact if there is post data available or not. If there is no post data Unity performs a GET request. Otherwise a POST. If the server doesn't expect any post data but you need to do a POST it doesn't hurt when you append one byte garbage post data ;)