HttpClient: The uri string is too long

2019-02-12 08:30发布

问题:

Given the following attempt to post data to a web service that generates PDF files, PDF rocket (which is awesome by the way).

I get the error Invalid URI: The uri string is too long
Why would anyone impose an arbitrary limit on POSTed data?

using (var client = new HttpClient())
{
    // Build the conversion options
    var options = new Dictionary<string, string>
    {
        { "value", html },
        { "apikey", ConfigurationManager.AppSettings["pdf:key"] },
        { "MarginLeft", "10" },
        { "MarginRight", "10" }
    };

    // THIS LINE RAISES THE EXCEPTION
    var content = new FormUrlEncodedContent(options);

    var response = await client.PostAsync("https://api.html2pdfrocket.com/pdf", content);
    var result = await response.Content.ReadAsByteArrayAsync();
    return result;
}

I receive this rediculous error.

 {System.UriFormatException: Invalid URI: The Uri string is too long.
   at System.UriHelper.EscapeString
   at System.Uri.EscapeDataString
   at System.Net.Http.FormUrlEncodedContent.Encode
   at System.Net.Http.FormUrlEncodedContent.GetContentByteArray

This reminds me of 640k ought to be enough... I mean really?

回答1:

With a post can include the content in the http message instead of the URI. A uri has a max length of 2083 characters. You could send it as JSON in the http message instead of the URI which is the recommended way to send larger chunks of data in an HttpPost/HttpPut. I altered your code to make use of it. This assumes that your service you are contacting can work with JSON (.net Web Api out of the box should have no problem with this).

using (var client = new HttpClient())
{
    // Build the conversion options
    var options = new 
    {
        value = html,
        apikey = ConfigurationManager.AppSettings["pdf:key"],
        MarginLeft = "10",
        MarginRight = "10"
    };

    // Serialize our concrete class into a JSON String
    var stringPayload = JsonConvert.SerializeObject(options);
    var content = new StringContent(stringPayload, Encoding.UTF8, "application/json");

    var response = await client.PostAsync("https://api.html2pdfrocket.com/pdf", content);
    var result = await response.Content.ReadAsByteArrayAsync();
    return result;
}

Make sure to install newtonsoft json.



回答2:

I just solved a similar problem. For me I was integrating with a backend I didn't control and had to POST file along with form data (eg customerID) as form variables. So switching to JSON or Multipart would break the backend I didn't control. The problem was that large files would cause the FormUrlEncodedContent to throw an error saying "The uri string is too long".

This is the code that solved it for me after two days of effort (note still needs to be tweaked to be ASYNC).

private string UploadFile(string filename, int CustomerID, byte[] ImageData) {

        string Base64String = "data:image/jpeg;base64," + Convert.ToBase64String(ImageData, 0, ImageData.Length);

        var baseAddress = new Uri("[PUT URL HERE]");
        var cookieContainer = new CookieContainer();
        using (var handler = new HttpClientHandler() { AllowAutoRedirect = true, UseCookies = true, CookieContainer = cookieContainer })
        using (var client = new HttpClient(handler) { BaseAddress = baseAddress })
        {

            try {

                //ENCODE THE FORM VARIABLES DIRECTLY INTO A STRING rather than using a FormUrlEncodedContent type which has a limit on its size.        
                string FormStuff = string.Format("name={0}&file={1}&id={2}", filename, HttpUtility.UrlEncode(Base64String), CustomerID.ToString());
                //THEN USE THIS STRING TO CREATE A NEW STRINGCONTENT WHICH TAKES A PARAMETER WHICH WILL FormURLEncode IT AND DOES NOT SEEM TO THROW THE SIZE ERROR
                StringContent content = new StringContent(FormStuff, Encoding.UTF8, "application/x-www-form-urlencoded");

                //UPLOAD
                string url = string.Format("/ajax/customer_image_upload.php");
                response = client.PostAsync(url, content).Result;
                return response.Content.ToString();

            }
            catch (Exception ex) {
                return ex.ToString();
            }



        }

    }


回答3:

@Mick Byrne : Thanks - your solution worked like a charme!

Here is my complete code:

      public async Task DateienSendenAsync (string PfadUndDatei, string Dateiname, String VRPinGUID, String ProjektGUID, String VRPinX, String VRPinY, String VRPinZ)
    {
        var client = new HttpClient();
        // Create the HttpContent for the form to be posted.
        var requestContent = new[] {
                            new KeyValuePair<string, string>("dateiname", Dateiname),

                            new KeyValuePair<string, string>("bild", Convert.ToBase64String(File.ReadAllBytes(PfadUndDatei))),
                            new KeyValuePair<string, string>("VRPinGUID", VRPinGUID),
                            new KeyValuePair<string, string>("ProjektGUID", ProjektGUID),
                            new KeyValuePair<string, string>("ebene", "ebene"),
                            new KeyValuePair<string, string>("raumnummer", "raumnummer"),
                            new KeyValuePair<string, string>("ansichtsname", "ansichtsname"),
                            new KeyValuePair<string, string>("VRPinX", VRPinX),
                            new KeyValuePair<string, string>("VRPinY", VRPinY),
                            new KeyValuePair<string, string>("VRPinZ", VRPinZ),

                            };

        String url = "http://yourhomepage/path/upload.php";

        var encodedItems = requestContent.Select(i => WebUtility.UrlEncode(i.Key) + "=" + WebUtility.UrlEncode(i.Value));
        var encodedContent = new StringContent(String.Join("&", encodedItems), null, "application/x-www-form-urlencoded");

        // Post away!
        var response = await client.PostAsync(url, encodedContent);



    }


回答4:

If, like me, you're faced with some wonky 3rd party web service that will only accept form content, you can work around the problem like this:

// Let's assume you've got your key-value pairs organised into a nice Dictionary<string, string> called formData
var encodedItems = formData.Select(i => WebUtility.UrlEncode(i.Key) + "=" + WebUtility.UrlEncode(i.Value));
var encodedContent = new StringContent(String.Join("&", encodedItems), null, "application/x-www-form-urlencoded");

// Post away!
var response = await client.PostAsync(url, encodedContent);