Cách tạo một yêu cầu web HTTP POST


1133

Canonical
Làm thế nào tôi có thể thực hiện một yêu cầu HTTP và gửi một số dữ liệu bằng POST phương thức này?

Tôi có thể thực hiện một GETyêu cầu, nhưng tôi không biết làm thế nào để thực hiện một POSTyêu cầu.

Câu trả lời:


2165

Có một số cách để thực hiện HTTP GETPOSTyêu cầu:


Phương pháp A: HttpClient (Được ưa thích)

Có sẵn trong: .NET Framework 4.5+, .NET Standard 1.1+, .NET Core 1.0+.

Nó hiện đang là phương pháp ưa thích và không đồng bộ và hiệu suất cao. Sử dụng phiên bản tích hợp trong hầu hết các trường hợp, nhưng đối với các nền tảng rất cũ có gói NuGet .

using System.Net.Http;

Thiết lập

Bạn nên khởi tạo một HttpClientứng dụng trong suốt vòng đời của ứng dụng và chia sẻ nó trừ khi bạn có lý do cụ thể không.

private static readonly HttpClient client = new HttpClient();

Xem HttpClientFactorycho một giải pháp tiêm phụ thuộc .


  • POST

    var values = new Dictionary<string, string>
    {
        { "thing1", "hello" },
        { "thing2", "world" }
    };
    
    var content = new FormUrlEncodedContent(values);
    
    var response = await client.PostAsync("http://www.example.com/recepticle.aspx", content);
    
    var responseString = await response.Content.ReadAsStringAsync();
  • GET

    var responseString = await client.GetStringAsync("http://www.example.com/recepticle.aspx");

Phương pháp B: Thư viện của bên thứ ba

RestSharp

  • POST

     var client = new RestClient("http://example.com");
     // client.Authenticator = new HttpBasicAuthenticator(username, password);
     var request = new RestRequest("resource/{id}");
     request.AddParameter("thing1", "Hello");
     request.AddParameter("thing2", "world");
     request.AddHeader("header", "value");
     request.AddFile("file", path);
     var response = client.Post(request);
     var content = response.Content; // Raw content as string
     var response2 = client.Post<Person>(request);
     var name = response2.Data.Name;

Flurl.Http

Đây là một thư viện mới hơn có API lưu loát, người trợ giúp kiểm tra, sử dụng HTTPClient dưới mui xe và có thể mang theo được. Nó có sẵn thông qua NuGet .

    using Flurl.Http;

  • POST

    var responseString = await "http://www.example.com/recepticle.aspx"
        .PostUrlEncodedAsync(new { thing1 = "hello", thing2 = "world" })
        .ReceiveString();
  • GET

    var responseString = await "http://www.example.com/recepticle.aspx"
        .GetStringAsync();

Phương pháp C: HttpWebRequest (không được đề xuất cho công việc mới)

Có sẵn trong: .NET Framework 1.1+, .NET Standard 2.0+, .NET Core 1.0+. Trong .NET Core, phần lớn là để tương thích - nó kết thúc tốt hơn HttpClient, ít hiệu năng hơn và sẽ không nhận được các tính năng mới.

using System.Net;
using System.Text;  // For class Encoding
using System.IO;    // For StreamReader

  • POST

    var request = (HttpWebRequest)WebRequest.Create("http://www.example.com/recepticle.aspx");
    
    var postData = "thing1=" + Uri.EscapeDataString("hello");
        postData += "&thing2=" + Uri.EscapeDataString("world");
    var data = Encoding.ASCII.GetBytes(postData);
    
    request.Method = "POST";
    request.ContentType = "application/x-www-form-urlencoded";
    request.ContentLength = data.Length;
    
    using (var stream = request.GetRequestStream())
    {
        stream.Write(data, 0, data.Length);
    }
    
    var response = (HttpWebResponse)request.GetResponse();
    
    var responseString = new StreamReader(response.GetResponseStream()).ReadToEnd();
  • GET

    var request = (HttpWebRequest)WebRequest.Create("http://www.example.com/recepticle.aspx");
    
    var response = (HttpWebResponse)request.GetResponse();
    
    var responseString = new StreamReader(response.GetResponseStream()).ReadToEnd();

Phương pháp D: WebClient (Không được khuyến nghị cho công việc mới)

Đây là một bọc xung quanh HttpWebRequest. So sánh vớiHttpClient .

Có sẵn trong: .NET Framework 1.1+, NET Standard 2.0+,.NET Core 2.0+

using System.Net;
using System.Collections.Specialized;

  • POST

    using (var client = new WebClient())
    {
        var values = new NameValueCollection();
        values["thing1"] = "hello";
        values["thing2"] = "world";
    
        var response = client.UploadValues("http://www.example.com/recepticle.aspx", values);
    
        var responseString = Encoding.Default.GetString(response);
    }
  • GET

    using (var client = new WebClient())
    {
        var responseString = client.DownloadString("http://www.example.com/recepticle.aspx");
    }

2
@Lloyd:HttpWebResponse response = (HttpWebResponse)HttpWReq.GetResponse();
Evan Mulawski

2
Tại sao bạn thậm chí sử dụng ASCII? Nếu ai đó cần xml với UTF-8 thì sao?
Gero

8
Tôi ghét đánh bại một con ngựa chết nhưng bạn nên làmresponse.Result.Content.ReadAsStringAsync()
David S.

13
Tại sao bạn nói WebRequest và WebClient là di sản? MSDN không nói rằng họ không được chấp nhận hoặc bất cứ điều gì. Tui bỏ lỡ điều gì vậy?
Hiệp

23
@Hiep: Chúng không bị phản đối, chỉ có những cách mới hơn (và hầu hết các trường hợp, tốt hơn và linh hoạt hơn) để thực hiện các yêu cầu web. Theo tôi, đối với các hoạt động đơn giản, không quan trọng, các cách cũ chỉ tốt - nhưng tùy thuộc vào bạn và bất cứ điều gì bạn cảm thấy thoải mái nhất.
Evan Mulawski

384

Yêu cầu NHẬN đơn giản

using System.Net;

...

using (var wb = new WebClient())
{
    var response = wb.DownloadString(url);
}

Yêu cầu POST đơn giản

using System.Net;
using System.Collections.Specialized;

...

using (var wb = new WebClient())
{
    var data = new NameValueCollection();
    data["username"] = "myUser";
    data["password"] = "myPassword";

    var response = wb.UploadValues(url, "POST", data);
    string responseInString = Encoding.UTF8.GetString(response);
}

15
+1 Đối với công cụ thông thường POST, thật tuyệt khi có đoạn mã ngắn như vậy.
dùng

3
Tim - Nếu bạn nhấp chuột phải vào nghĩa đen không thể giải quyết, bạn sẽ tìm thấy menu Giải quyết ngữ cảnh, trong đó có các hành động để thêm các câu lệnh Sử dụng cho bạn. Nếu menu ngữ cảnh Giải quyết không hiển thị, điều đó có nghĩa là bạn cần thêm tài liệu tham khảo trước.
Cameron Wilby

Tôi chấp nhận câu trả lời của bạn là tốt bởi vì nó đơn giản và rõ ràng hơn nhiều.
Hooch

13
Tôi muốn thêm rằng biến trả lời cho yêu cầu POST là một mảng byte. Để có được phản hồi chuỗi, bạn chỉ cần thực hiện Encoding.ASCII.GetString (hồi đáp); (sử dụng System.Text)
Sindre

1
Hơn nữa, bạn có thể gửi một mảng phức tạp một chút $ _POST ['user'] dưới dạng: data ["user [username]"] = "myUsername"; dữ liệu ["người dùng [mật khẩu]"] = "myPassword";
Boudel Poudel

68

MSDN có một mẫu.

using System;
using System.IO;
using System.Net;
using System.Text;

namespace Examples.System.Net
{
    public class WebRequestPostExample
    {
        public static void Main()
        {
            // Create a request using a URL that can receive a post. 
            WebRequest request = WebRequest.Create("http://www.contoso.com/PostAccepter.aspx");
            // Set the Method property of the request to POST.
            request.Method = "POST";
            // Create POST data and convert it to a byte array.
            string postData = "This is a test that posts this string to a Web server.";
            byte[] byteArray = Encoding.UTF8.GetBytes(postData);
            // Set the ContentType property of the WebRequest.
            request.ContentType = "application/x-www-form-urlencoded";
            // Set the ContentLength property of the WebRequest.
            request.ContentLength = byteArray.Length;
            // Get the request stream.
            Stream dataStream = request.GetRequestStream();
            // Write the data to the request stream.
            dataStream.Write(byteArray, 0, byteArray.Length);
            // Close the Stream object.
            dataStream.Close();
            // Get the response.
            WebResponse response = request.GetResponse();
            // Display the status.
            Console.WriteLine(((HttpWebResponse)response).StatusDescription);
            // Get the stream containing content returned by the server.
            dataStream = response.GetResponseStream();
            // Open the stream using a StreamReader for easy access.
            StreamReader reader = new StreamReader(dataStream);
            // Read the content.
            string responseFromServer = reader.ReadToEnd();
            // Display the content.
            Console.WriteLine(responseFromServer);
            // Clean up the streams.
            reader.Close();
            dataStream.Close();
            response.Close();
        }
    }
}

Vì một số lý do, nó không hoạt động khi tôi gửi một lượng lớn dữ liệu
AnKing

26

Đây là một ví dụ hoạt động hoàn chỉnh về việc gửi / nhận dữ liệu ở định dạng JSON, tôi đã sử dụng Visual Studio 2013 Express Edition:

using System;
using System.Collections.Generic;
using System.Data;
using System.Data.OleDb;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using System.Web.Script.Serialization;

namespace ConsoleApplication1
{
    class Customer
    {
        public string Name { get; set; }
        public string Address { get; set; }
        public string Phone { get; set; }
    }

    public class Program
    {
        private static readonly HttpClient _Client = new HttpClient();
        private static JavaScriptSerializer _Serializer = new JavaScriptSerializer();

        static void Main(string[] args)
        {
            Run().Wait();
        }

        static async Task Run()
        {
            string url = "http://www.example.com/api/Customer";
            Customer cust = new Customer() { Name = "Example Customer", Address = "Some example address", Phone = "Some phone number" };
            var json = _Serializer.Serialize(cust);
            var response = await Request(HttpMethod.Post, url, json, new Dictionary<string, string>());
            string responseText = await response.Content.ReadAsStringAsync();

            List<YourCustomClassModel> serializedResult = _Serializer.Deserialize<List<YourCustomClassModel>>(responseText);

            Console.WriteLine(responseText);
            Console.ReadLine();
        }

        /// <summary>
        /// Makes an async HTTP Request
        /// </summary>
        /// <param name="pMethod">Those methods you know: GET, POST, HEAD, etc...</param>
        /// <param name="pUrl">Very predictable...</param>
        /// <param name="pJsonContent">String data to POST on the server</param>
        /// <param name="pHeaders">If you use some kind of Authorization you should use this</param>
        /// <returns></returns>
        static async Task<HttpResponseMessage> Request(HttpMethod pMethod, string pUrl, string pJsonContent, Dictionary<string, string> pHeaders)
        {
            var httpRequestMessage = new HttpRequestMessage();
            httpRequestMessage.Method = pMethod;
            httpRequestMessage.RequestUri = new Uri(pUrl);
            foreach (var head in pHeaders)
            {
                httpRequestMessage.Headers.Add(head.Key, head.Value);
            }
            switch (pMethod.Method)
            {
                case "POST":
                    HttpContent httpContent = new StringContent(pJsonContent, Encoding.UTF8, "application/json");
                    httpRequestMessage.Content = httpContent;
                    break;

            }

            return await _Client.SendAsync(httpRequestMessage);
        }
    }
}

8

Có một số câu trả lời thực sự tốt ở đây. Hãy để tôi đăng một cách khác để đặt tiêu đề của bạn với WebClient (). Tôi cũng sẽ chỉ cho bạn cách đặt khóa API.

        var client = new WebClient();
        string credentials = Convert.ToBase64String(Encoding.ASCII.GetBytes(userName + ":" + passWord));
        client.Headers[HttpRequestHeader.Authorization] = $"Basic {credentials}";
        //If you have your data stored in an object serialize it into json to pass to the webclient with Newtonsoft's JsonConvert
        var encodedJson = JsonConvert.SerializeObject(newAccount);

        client.Headers.Add($"x-api-key:{ApiKey}");
        client.Headers.Add("Content-Type:application/json");
        try
        {
            var response = client.UploadString($"{apiurl}", encodedJson);
            //if you have a model to deserialize the json into Newtonsoft will help bind the data to the model, this is an extremely useful trick for GET calls when you have a lot of data, you can strongly type a model and dump it into an instance of that class.
            Response response1 = JsonConvert.DeserializeObject<Response>(response);

Hữu ích, cảm ơn. BTW Có vẻ như kỹ thuật trên để thiết lập các thuộc tính tiêu đề cũng hoạt động đối với cách tiếp cận cũ hơn (không dùng nữa?), HttpWebRequest. ví dụ: myReq.Headers [HttpRequestHeader.Authorization] = $ "Basic {thông tin xác thực}";
Zeek2

6

Giải pháp này không sử dụng gì ngoài các cuộc gọi .NET tiêu chuẩn.

Thử nghiệm:

  • Sử dụng trong một ứng dụng WPF dành cho doanh nghiệp. Sử dụng async / await để tránh chặn UI.
  • Tương thích với .NET 4.5+.
  • Đã kiểm tra không có tham số (yêu cầu "NHẬN" phía sau hậu trường).
  • Đã kiểm tra với các tham số (yêu cầu "POST" phía sau hậu trường).
  • Đã thử nghiệm với một trang web tiêu chuẩn như Google.
  • Đã thử nghiệm với một dịch vụ web dựa trên Java nội bộ.

Tài liệu tham khảo:

// Add a Reference to the assembly System.Web

Mã số:

using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
using System.Web;

private async Task<WebResponse> CallUri(string url, TimeSpan timeout)
{
    var uri = new Uri(url);
    NameValueCollection rawParameters = HttpUtility.ParseQueryString(uri.Query);
    var parameters = new Dictionary<string, string>();
    foreach (string p in rawParameters.Keys)
    {
        parameters[p] = rawParameters[p];
    }

    var client = new HttpClient { Timeout = timeout };
    HttpResponseMessage response;
    if (parameters.Count == 0)
    {
        response = await client.GetAsync(url);
    }
    else
    {
        var content = new FormUrlEncodedContent(parameters);
        string urlMinusParameters = uri.OriginalString.Split('?')[0]; // Parameters always follow the '?' symbol.
        response = await client.PostAsync(urlMinusParameters, content);
    }
    var responseString = await response.Content.ReadAsStringAsync();

    return new WebResponse(response.StatusCode, responseString);
}

private class WebResponse
{
    public WebResponse(HttpStatusCode httpStatusCode, string response)
    {
        this.HttpStatusCode = httpStatusCode;
        this.Response = response;
    }
    public HttpStatusCode HttpStatusCode { get; }
    public string Response { get; }
}

Để gọi mà không có tham số (sử dụng "NHẬN" phía sau hậu trường):

 var timeout = TimeSpan.FromSeconds(300);
 WebResponse response = await this.CallUri("http://www.google.com/", timeout);
 if (response.HttpStatusCode == HttpStatusCode.OK)
 {
     Console.Write(response.Response); // Print HTML.
 }

Để gọi với các tham số (sử dụng "POST" phía sau hậu trường):

 var timeout = TimeSpan.FromSeconds(300);
 WebResponse response = await this.CallUri("http://example.com/path/to/page?name=ferret&color=purple", timeout);
 if (response.HttpStatusCode == HttpStatusCode.OK)
 {
     Console.Write(response.Response); // Print HTML.
 }

6

Giải pháp đơn giản (một lớp lót, không kiểm tra lỗi, không chờ phản hồi) Tôi đã tìm thấy cho đến nay:

(new WebClient()).UploadStringAsync(new Uri(Address), dataString);‏

Sử dụng cẩn thận!


5
Điều đó khá tệ. Tôi không khuyên bạn vì nó không có lỗi xử lý dưới bất kỳ hình thức nào và gỡ lỗi nó là nỗi đau. Ngoài ra, đã có câu trả lời tuyệt vời cho câu hỏi này.
Hooch

1
@Hooch những người khác có thể quan tâm đến loại câu trả lời này, ngay cả khi nó không phải là câu trả lời hay nhất.
Mitulát báti 30/12/17

Đồng ý, bối cảnh duy nhất mà điều này sẽ hữu ích là chơi golf mã và ai chơi golf trong C #;)
Extragorey

4

Khi sử dụng không gian tên Windows.Web.Http , đối với POST thay vì FormUrlEncodingContent, chúng tôi viết httpFormUrlEncodingContent. Ngoài ra, phản hồi là loại httpResponseMessage. Phần còn lại là như Evan Mulawski đã viết ra.


4

Nếu bạn thích một API thông thạo, bạn có thể sử dụng Tiny.RestClient . Nó có sẵn tại NuGet .

var client = new TinyRestClient(new HttpClient(), "http://MyAPI.com/api");
// POST
var city = new City() { Name = "Paris", Country = "France" };
// With content
var response = await client.PostRequest("City", city)
                           .ExecuteAsync<bool>();

1

Tại sao điều này không hoàn toàn tầm thường? Việc thực hiện yêu cầu không phải và đặc biệt là không xử lý kết quả và có vẻ như cũng có một số lỗi .NET liên quan - hãy xem Lỗi trong HttpClient.GetAsync nên ném WebException, không phải là Hủy bỏ nhiệm vụ

Tôi đã kết thúc với mã này:

static async Task<(bool Success, WebExceptionStatus WebExceptionStatus, HttpStatusCode? HttpStatusCode, string ResponseAsString)> HttpRequestAsync(HttpClient httpClient, string url, string postBuffer = null, CancellationTokenSource cts = null) {
    try {
        HttpResponseMessage resp = null;

        if (postBuffer is null) {
            resp = cts is null ? await httpClient.GetAsync(url) : await httpClient.GetAsync(url, cts.Token);

        } else {
            using (var httpContent = new StringContent(postBuffer)) {
                resp = cts is null ? await httpClient.PostAsync(url, httpContent) : await httpClient.PostAsync(url, httpContent, cts.Token);
            }
        }

        var respString = await resp.Content.ReadAsStringAsync();
        return (resp.IsSuccessStatusCode, WebExceptionStatus.Success, resp.StatusCode, respString);

    } catch (WebException ex) {
        WebExceptionStatus status = ex.Status;
        if (status == WebExceptionStatus.ProtocolError) {
            // Get HttpWebResponse so that you can check the HTTP status code.
            using (HttpWebResponse httpResponse = (HttpWebResponse)ex.Response) {
                return (false, status, httpResponse.StatusCode, httpResponse.StatusDescription);
            }
        } else {
            return (false, status, null, ex.ToString()); 
        }

    } catch (TaskCanceledException ex) {
        if (cts is object && ex.CancellationToken == cts.Token) {
            // a real cancellation, triggered by the caller
            return (false, WebExceptionStatus.RequestCanceled, null, ex.ToString());
        } else {
            // a web request timeout (possibly other things!?)
            return (false, WebExceptionStatus.Timeout, null, ex.ToString());
        }

    } catch (Exception ex) {
        return (false, WebExceptionStatus.UnknownError, null, ex.ToString());
    }
}

Điều này sẽ làm một GET hoặc POST phụ thuộc nếu postBufferlà null hay không

Nếu thành công là sự thật thì câu trả lời sẽ có ResponseAsString

nếu thành công là sai bạn có thể kiểm tra WebExceptionStatus, HttpStatusCodeResponseAsStringcố gắng để xem những gì đã xảy ra.


0

Trong lõi .net, bạn có thể thực hiện cuộc gọi sau bằng mã sau, ở đây tôi đã thêm một số tính năng bổ sung vào mã này để có thể làm cho mã của bạn hoạt động sau proxy và với thông tin mạng nếu có, ở đây tôi cũng đề cập rằng bạn có thể thay đổi mã hóa tin nhắn của bạn. Tôi hy vọng điều này giải thích tất cả và giúp bạn trong việc mã hóa.

HttpClient client = GetHttpClient(_config);

        if (headers != null)
        {
            foreach (var header in headers)
            {
                client.DefaultRequestHeaders.TryAddWithoutValidation(header.Key, header.Value);
            }
        }

        client.BaseAddress = new Uri(baseAddress);

        Encoding encoding = Encoding.UTF8;


        var result = await client.PostAsync(url, new StringContent(body, encoding, "application/json")).ConfigureAwait(false);
        if (result.IsSuccessStatusCode)
        {
            return new RequestResponse { severity = "Success", httpResponse = result.Content.ReadAsStringAsync().Result, StatusCode = result.StatusCode };
        }
        else
        {
            return new RequestResponse { severity = "failure", httpResponse = result.Content.ReadAsStringAsync().Result, StatusCode = result.StatusCode };
        }


 public HttpClient GetHttpClient(IConfiguration _config)
        {
            bool ProxyEnable = Convert.ToBoolean(_config["GlobalSettings:ProxyEnable"]);

            HttpClient client = null;
            if (!ProxyEnable)
            {
                client = new HttpClient();
            }
            else
            {
                string ProxyURL = _config["GlobalSettings:ProxyURL"];
                string ProxyUserName = _config["GlobalSettings:ProxyUserName"];
                string ProxyPassword = _config["GlobalSettings:ProxyPassword"];
                string[] ExceptionURL = _config["GlobalSettings:ExceptionURL"].Split(';');
                bool BypassProxyOnLocal = Convert.ToBoolean(_config["GlobalSettings:BypassProxyOnLocal"]);
                bool UseDefaultCredentials = Convert.ToBoolean(_config["GlobalSettings:UseDefaultCredentials"]);

                WebProxy proxy = new WebProxy
                {
                    Address = new Uri(ProxyURL),
                    BypassProxyOnLocal = BypassProxyOnLocal,
                    UseDefaultCredentials = UseDefaultCredentials,
                    BypassList = ExceptionURL,
                    Credentials = new NetworkCredential(ProxyUserName, ProxyPassword)

                };

                HttpClientHandler handler = new HttpClientHandler { Proxy = proxy };
                client = new HttpClient(handler,true);
            }
            return client;
        }
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.