如何使用 WebRequest,HttpWebRequest 來存取(GET,POST,PUT,DELETE,PATCH)網路資源

現在雲端服務多元,很多系統設計上也都走向 api 化的架構,加上前端工程以及 mobile 裝置的普及,使用後端程式呼叫外部 api 的情境也常遇到,.NET Framework 幫我們封裝了好幾個 api ,讓我們可以快速開發,但也因為有好幾個 api 可以使用而造成不知道該用哪一個,所以就想來釐清其中的差異,首先就先來看看 WebRequest 與 HttpWebRequest,因為兩者有繼承關係所以放在一起看

WebRequest 基本資訊

用來對 URI 提出 request,是個 abstract class,需使用 Create 而不是建構式來初始化 WebRequest instance

  • Namespace:System.Net
  • Assembly:System (System.dll)
  • 基本要求:.NET Framework 1.1 以上
  • 包含 HttpWebRequest,FtpWebRequest,FileWebRequest

HttpWebRequest 基本資訊

基於 WebRequest 實作 HTTP 相關功能,WebRequest 還另外包含 FtpWebRequest 及 FileWebRequest

  • Namespace:System.Net
  • Assembly:System (System.dll)
  • 基本要求:.NET Framework 1.1 以上
  • 因為基於 WebRequest 的實作,因此用法上也幾乎與 WebRequest 相同

1. GET

//建立 WebRequest 並指定目標的 uri
WebRequest request = WebRequest.Create("http://jsonplaceholder.typicode.com/posts");
// 使用 HttpWebRequest.Create 實際上也是呼叫 WebRequest.Create
//WebRequest request = HttpWebRequest.Create("http://jsonplaceholder.typicode.com/posts");

//指定 request 使用的 http verb
request.Method = "GET";
//使用 GetResponse 方法將 request 送出,如果不是用 using 包覆,請記得手動 close WebResponse 物件,避免連線持續被佔用而無法送出新的 request
using (var httpResponse = (HttpWebResponse)request.GetResponse())
//使用 GetResponseStream 方法從 server 回應中取得資料,stream 必需被關閉
//使用 stream.close 就可以直接關閉 WebResponse 及 stream,但同時使用 using 或是關閉兩者並不會造成錯誤,養成習慣遇到其他情境時就比較不會出錯
using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
    var result = streamReader.ReadToEnd();
    result.Dump();
}

2. POST (使用 application/json)

  • 指定 content type
  • 指定 header

    //建立 WebRequest 並指定目標的 uri
    WebRequest request = WebRequest.Create("https://jsonbin.org/me/test");
    //指定 request 使用的 http verb
    request.Method = "POST";
    //準備 post 用資料
    PostData postData = new PostData() { userId = 1, title = "yowko", body = "yowko test body 中文" };
    //指定 request 的 content type
    request.ContentType = "application/json; charset=utf-8";
    //指定 request header
    request.Headers.Add("authorization", "token apikey");
    //將需 post 的資料內容轉為 stream 
    using (var streamWriter = new StreamWriter(request.GetRequestStream()))
    {
        string json = new JavaScriptSerializer().Serialize(postData);
        streamWriter.Write(json);
        streamWriter.Flush();
    }
    //使用 GetResponse 方法將 request 送出,如果不是用 using 包覆,請記得手動 close WebResponse 物件,避免連線持續被佔用而無法送出新的 request
    using (var httpResponse = (HttpWebResponse)request.GetResponse())
    //使用 GetResponseStream 方法從 server 回應中取得資料,stream 必需被關閉
    //使用 stream.close 就可以直接關閉 WebResponse 及 stream,但同時使用 using 或是關閉兩者並不會造成錯誤,養成習慣遇到其他情境時就比較不會出錯
    using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
    {
        var result = streamReader.ReadToEnd();
        result.Dump();
    }
    

3. POST(使用 application/x-www-form-urlencoded)

WebRequest request = HttpWebRequest.Create("https://jsonbin.org/me/test");
request.Method = "POST";
//使用 application/x-www-form-urlencoded
request.ContentType = "application/x-www-form-urlencoded; charset=utf-8";
request.Headers.Add("authorization", "token apikey");
//要傳送的資料內容(依字串表示)
string postData = "id=9&name=yowko&body=yowko中文";
//將傳送的字串轉為 byte array
byte[] byteArray = Encoding.UTF8.GetBytes(postData);
//告訴 server content 的長度
request.ContentLength = byteArray.Length;
//將 byte array 寫到 request stream 中 
using (Stream reqStream = request.GetRequestStream())
{
    reqStream.Write(byteArray, 0, byteArray.Length);
}
using (var httpResponse = (HttpWebResponse)request.GetResponse())
using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
    var result = streamReader.ReadToEnd();
    result.Dump();
}

4. PUT

WebRequest request = WebRequest.Create("https://jsonbin.org/yowko/test/_perms");
request.Method = "PUT";
request.Headers.Add("authorization", "token apikey");
using (var httpResponse = (HttpWebResponse)request.GetResponse())
using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
    var result = streamReader.ReadToEnd();
    result.Dump();
}

5. DELETE

WebRequest request = WebRequest.Create("https://jsonbin.org/yowko/test/_perms");
request.Method = "DELETE";
request.Headers.Add("authorization", "token apikey");
using (var httpResponse = (HttpWebResponse)request.GetResponse())
using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
    var result = streamReader.ReadToEnd();
    result.Dump();
}

6. PATCH

WebRequest request = WebRequest.Create("https://jsonbin.org/me/test");
request.Method = "PATCH";
PostData postData = new PostData() { body = "yowko test body 中文2" };
request.ContentType = "application/json; charset=utf-8";
request.Headers.Add("authorization", "token apikey");
using (var streamWriter = new StreamWriter(request.GetRequestStream()))
{
    string json = new JavaScriptSerializer().Serialize(postData);
    streamWriter.Write(json);
    streamWriter.Flush();
}

using (var httpResponse = (HttpWebResponse)request.GetResponse())
using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
    var result = streamReader.ReadToEnd();
    result.Dump();
}

7. 使用 proxy

有時候程式的 host 環境無法直接上網或是我們想要確認傳出去的相關資訊,就需要設定 proxy

WebRequest request = WebRequest.Create("https://jsonbin.org/me/test");
request.Method = "POST";
PostData postData = new PostData() { userId = 1, title = "yowko1", body = "yowko test body 中文" };
request.ContentType = "application/json; charset=utf-8";
request.Headers.Add("authorization", "token apikey");
//指令 proxy address
string proxyAddress="http://127.0.0.1:8888";
//建立 proxy
WebProxy myProxy=new WebProxy(new Uri(proxyAddress));
//建立 proxy 的認證資訊
myProxy.Credentials=new NetworkCredential("{username}","{password}");
//將 proxy 指定給 request 使用
request.Proxy=myProxy;
using (var streamWriter = new StreamWriter(request.GetRequestStream()))
{
    string json = new JavaScriptSerializer().Serialize(postData);
    streamWriter.Write(json);
    streamWriter.Flush();
}
using (var httpResponse = (HttpWebResponse)request.GetResponse())
using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
    var result = streamReader.ReadToEnd();
    result.Dump();
}

參考資料

  1. WebRequest 類別
  2. 如何:使用 WebRequest 類別傳送資料
  3. 如何:使用 WebRequest 類別要求資料
  4. HttpWebRequest 類別