Gửi các Request POST và GET trong C#


Đã hơn 6 tháng kể từ khi mình post lên blog một bài viết mới. Nhận thấy rằng vẫn có nhiều bạn quan tâm và comment trên blog này cho nên lại phải đưa ra một quyết tâm mới là tiếp tục viết bài cho blog này. Dẫu biết rằng có thể 6 tháng tiếp theo nữa mới có một bài viết mới, nhưng biết sao được, có còn hơn không ^_^.

Hôm nay chúng ta sẽ tìm hiểu về phương pháp gửi các request dạng POST và GET trong C#. Bằng cách này bạn có thể lấy được nhiều dữ liệu hữu ích từ các trang web để phục vụ cho công việc của mình.

Mục tiêu của bài viết này là chúng ta sẽ viết được ứng dụng xem lịch phát sóng các kênh truyền hình của iTV. Trang web thông thường để xem lịch phát sóng là http://itv.vn/Lichphatsong.aspx. Trong trang web này, khi bạn click chọn một kênh trong danh sách hoặc chọn ngày phát sóng thì ngay lập tức lịch phát sóng bên dưới sẽ được cập nhật mà trang web không cần phải reload. Đây là kỹ thuật AJAX thường được dùng trên web hiện nay

AJAX (Asynchronous Javascript And XML) là kỹ thuật lập trình web sử dụng Javascript và đối tượng XmlHttpRequest nhằm giao tiếp với server mà không cần phải reload lại trang web trên trình duyệt, từ đó tạo cảm giác tương tác cao giữa người dùng và trang web như là đang sử dụng một ứng dụng desktop. Nếu muốn bắt đầu tìm hiểu về AJAX, bạn có thể vào link: http://www.w3schools.com/ajax/

Trở lại với trang web lịch phát sóng ở trên, rõ ràng đã có một request gửi đến server yêu cầu trả về lịch phát sóng cho một kênh truyền hình tại một thời điểm nào đó. Để theo dõi được những Request này, bạn hãy sử dụng các công cụ để theo dõi thông tin về những Request được gửi giữa trình duyệt và server. Trong Firefox thì công cụ (Add-on) nổi tiếng nhất và được các nhà phát triển Web ưa chuộng nhất là Firebug. Trong Chrome và IE thì đã được tích hợp sẵn công cụ Developer Tool. Các bạn có thể nhấn F12 để mở khung công cụ này

image

Trong khung công cụ (trên Google Chrome), các bạn có thể nhận thấy rất nhiều Tab khác nhau phục vụ cho những mục đích khác nhau. Elements là tab để bạn xem cấu trúc DOM của trang web, Resources là tab dùng để xem các tài nguyên mà trang web sử dụng, ví dụ các file CSS, các hình ảnh, cookies… Network là tab để theo dõi Request giữa browser và trình duyệt, Scripts là tab bạn dùng để debug code javascript. Timeline là tab để bạn theo dõi thời gian xử lý của tất cả các sự kiện trên trang web. Profiles là nơi bạn ghi lại thời gian thực hiện các hàm Javascript cũng như bộ nhớ được sử dụng như thế nào. Audits là thành phần giúp bạn phân tích trang web cũng như đưa ra các gợi ý để tối ưu trang web. Console là tab để biết được các lỗi hay cảnh báo xảy ra ở trang web như lỗi Javascript, lỗi cấu trúc HTML… Trong bài viết này, chúng ta sẽ tập trung vào việc sử dụng tab Network nhằm phân tích nội dung Request được gửi đến Server cũng như là nội dung được trả về từ Server.

Với tab Network được mở, các bạn hãy thử chọn một kênh truyền hình. Khi đó sẽ có một Request được phát sinh

image

Nhìn lướt qua thông tin trong công cụ, ta có thể biết được rằng: Khi chọn một kênh, sẽ có một Request được gửi đến địa chỉ Lichphatsong.aspx bằng phương thức POST, và request này đã thành công. Các bạn click vào thông tin này để xem được chi tiết nội dung

image

Thông tin chi tiết của mỗi Request được chia thành 4 nhãn riêng: Headers, Preview, Response và Timing. Nhãn Headers sẽ chứa nội dung của Request đã được gửi tới Server là gì, ví dụ Content-Type, Date… Trong đó, thông tin quan trọng nhất chính là Form Data. Đây là dữ liệu đi kèm với Request, được gửi đến Server để lấy thông tin về. Ví dụ trên hình, request của ta sẽ có dữ liệu là một biến hdnChannel (chính là mã số của kênh truyền hình được chọn), biến hdnDate là ngày phát sóng của kênh mà cần lấy thông tin, còn biến hdnIsAjax thì dùng để cho biết request này có phát sinh từ AJAX hay không (không có biến này thì dữ liệu gửi về sẽ là một trang web HTML thay vì dữ liệu XML). Các thông tin này chính là những dữ liệu chúng ta đã chọn ở trên trang web thông qua các ComboBox.

Nhãn Preview và Response sẽ chứa nội dung được trả về từ Server. Response chứa dữ liệu ở dạng raw, tức là nếu dữ liệu trả về một trang web HTML, bạn sẽ thấy được mã HTML của trang web đó. Nhãn Preview là nội dung nhưng hiển thị giống như là ta đang xem một trang web. Nghĩa là nếu Server trả về một trang web thì nhãn Preview sẽ hiển thị trang web đó với đầy đủ định dạng như ta đang xem trong trình duyệt thông thường. Trong trường hợp của chúng ta, vì dữ liệu trả về thuộc dạng XML cho nên cả Response và Preview đều hiển thị dạng text thông thường.

image

Như vậy, ta đã biết cần gửi lên server những gì và dữ liệu được trả về là gì, việc tiếp theo là việc mà tất cả các nhà phát triển đều thích và ghét: lập trình!!!!!!!!!!!!!!!!.

Giao diện của chương trình như sau:

image

Chương trình này có định nghĩa 2 class dùng để chứa thông tin. Class ChannelItem là lưu trữ thông tin về các kênh (bao gồm Id và tên), class ProgramItem dùng để lưu trữ các chương trình của lịch phát sóng (bao gồm thời gian và nội dung). Mục đích chính của 2 class này là để việc hiển thị trên ComboBox và ListView dễ dàng hơn.

Phần quan trọng nhất của chương trình là đoạn code sau:

//Get channel ID and date
ChannelItem channel = cmbChannel.SelectedItem as ChannelItem;
DateTime date = datePicker.Value;

//Set up a request object
WebRequest request = WebRequest.Create("http://itv.vn/Lichphatsong.aspx");

//Specify the method: POST or GET
request.Method = "POST"; 
            
//data we want to send is included here
string data = string.Format("hdnChannel={0}&hdnDate={1}&hdnIsAjax=0", channel.Id, date.ToString("dd/MM/yyyy"));

//convert the data into byte array
byte[] byteArray = Encoding.UTF8.GetBytes(data);

//set Content-Length and Content-Type 
request.ContentLength = byteArray.Length;
request.ContentType = "application/x-www-form-urlencoded";

//get the request stream and write data to it and close it
Stream dataStream = request.GetRequestStream();
dataStream.Write(byteArray, 0, byteArray.Length);
dataStream.Close();

//Now the real request is called here when we call the GetResponse method
WebResponse response = request.GetResponse();

//Get the data from the Response
dataStream = response.GetResponseStream();

//Open stream using XMLTextReader
XmlTextReader reader = new XmlTextReader(dataStream);

try
{
    //Process the XML to display on the form
    XDocument xmlDoc = XDocument.Load(reader);

    List programs = new List(); //list to hold data

    foreach (var item in xmlDoc.Element("response").Elements("nut"))
    {
        ProgramItem program = new ProgramItem
        {
            Time = item.Attribute("Times").Value,
            Content = item.Attribute("Programs").Value
        };
        programs.Add(program);
    }

Trước hết, chúng ta lấy ra mã kênh được chọn và ngày phát sóng. Sau đó tạo một đối tượng WebRequest để thực hiện gửi request đến Server. Phương thức WebRequest.Create nhận tham số đầu vào là địa chỉ mà chúng ta sẽ gửi Request đến. Theo mặc định, method của đối tượng WebRequest sẽ là GET, do đó chúng ta cần phải thay đổi giá trị thuộc tính Method sang thành POST, nếu không lời gọi của chúng ta sẽ cho kết quả không đúng.

Để gửi dữ liệu lên Server theo đúng những gì chúng ta đã thấy trong công cụ Developer tool của Chrome thì chúng ta tạo ra một chuỗi dữ liệu cần gửi. Chuỗi này chứa dữ liệu theo dạng <tên biến>=<giá trị>&<tên biến>=<giá trị>&… (Chắc một số bạn đã từng lập trình web sẽ thấy nó giống như QueryString trên URL trong phương thức GET). Lưu ý rằng theo như thông tin trong Developer Tools thì Request phải gửi biến hdnDate ở dạng dd/MM/yyyy, do đó chúng ta cần sử dụng phương thức ToString trên biến date để định dạng lại ngày tháng cho chính xác.

Các dòng code tiếp theo là để đưa chuỗi dữ liệu ở trên vào Request. Đầu tiên là chuyển chuỗi dữ liệu sang thành một mảng byte, sau đó là thiết lập giá trị ContentLength (chính là độ dài của mảng byte) và ContentType (tương ứng với thông tin trong Developer Tools). Cuối cùng là ghi dữ liệu đó vào Request thông qua RequestStream

Tất cả các bước ở trên là chỉ nhằm chuẩn bị cho lời gọi đến Server, chứ thực sự chúng ta vẫn chưa gửi Request đó đến Server. Chỉ khi chúng ta gọi phương thức GetResponse() của đối tượng request thì khi đó request mới được gửi đến server, và dữ liệu trả về của server sẽ được đưa vào trong đối tượng WebResponse. Đây là phương thức dạng synchronous (đồng bộ), vì vậy ứng dụng sẽ dừng cho đến khi nào có kết quả trả về từ server hoặc timeout, do đó nếu như chúng ta gửi Request đến một server mà server chưa trả dữ liệu về thì ứng dụng của chúng ta có thể bị treo (khi đó các bạn có thể cân nhắc đến việc sử dụng phương thức BeginGetResponse để thực hiện gửi request theo dạng asynchronous – bất đồng bộ). Chúng ta chỉ cần đọc dữ liệu từ đối tượng này thông qua XmlTextReader là có được nội dung của dữ liệu trả về ở dạng XML.

Trong khối try…catch là đoạn mã xử lý dữ liệu XML đã nhận được để chuyển nó thành danh sách các đối tượng ProgramItem. Nếu bạn chưa rõ về cách xử lý tài liệu XML bằng LINQ thì bạn có thể tham khảo bài viết: Load file XML bằng LINQ. Kết thúc bước này thì chúng ta đã hoàn thành việc gửi Request lên Server và xử lý dữ liệu nhận về. Việc cuối cùng là đưa dữ liệu này lên ListView để hiển thị ra cho người dùng.

Các bạn có thể download source code của chương trình tại đây: iTV.zip

Kết luận: Bài viết này hướng dẫn các bạn thực hiện việc gửi request đến Server trong C# bằng phương thức POST cũng như xử lý dữ liệu nhận được từ request đó. Đối với các Request ở dạng GET thì việc xử lý cũng tương tự vì chúng ta sẽ không có bước đưa dữ liệu vào trong Request mà đưa dữ liệu đó thông qua QueryString ngay tại phương thức WebRequest.Create. Trong bài sau, chúng ta sẽ cùng nhau tìm hiểu cách sử dụng phương pháp này để crawl dữ liệu từ các trang web.

Tác giả: xuanchien

Tran Xuan Chien. Japan Advanced Institute of Science and Technology - Japan. Senior Developer - NUS Technology.

19 thoughts on “Gửi các Request POST và GET trong C#”

  1. Thanks bạn, bài viết rất hay.

    Mình cũng đang tìm hiểu về vấn đề này. Mình muốn viết một chương trình sử dụng phương thức POST của http để login vào một website.

    Mình theo dõi dữ liệu trao đổi giữa trình duyệt và server thì thấy phần nội dung (content) của gói tin POST gửi lên server không chỉ đơn giản chứa usename và password mà chứa một chuỗi các kí tự rất dài không hiểu là gì

    Bạn có biết chuỗi đó được tạo ra như thế nào không ?

    Thanks bạn

      1. ^^ Thanks bạn nhiều nha,

        Đúng là trong chuỗi dài đó có chứa rất nhiều cặp {key,value} được mã hóa theo kiểu urlencode,

        Các key đó gồm có: ScriptManager,
        StylesheetManager_TSSM,
        ScriptManager_TSM,
        LASTFOCUS
        EVENTTARGET
        EVENTARGUMENT
        VIEWSTATE
        VIEWSTATEENCRYPTED
        EVENTVALIDATION
        Username
        Password
        ScrollTop
        dnnVariable
        ASYNCPOST

        Mình còn có một thắc mắc là tại sao cặp key Username và Password không bị biến đổi hay mã hóa gì cả.

        Mình đã xem thử một số trang web khi login, 2 key này vẫn để ở dạng string bình thường.

        Lỡ như gói tin của mình bị bắt bởi một bên thứ 3 thì dữ liệu login của mình đã bị lộ rồi, đúng không bạn ?

        Thanks bạn, ^^

      2. Đúng như vậy, chỉ khi nào trang web đó sử dụng SSL thì các thông tin này mới không thể (hoặc chưa thể ^_^) bị xem. Đó là lý do mà các trang web của các hãng lớn hay ngân hàng… đều có sử dụng SSL trên trang login.

  2. Chào bạn,
    Mình đang làm 1 project viết trình auto can thiệp vào web. Bạn có tài liệu nào về web crawler thì share mình với, mình tìm hoài trên mạng mà ko có tài liệu liên quan.
    Email mình: noone.tk@gmail.com
    Rất vui nếu được trao đổi cùng bạn.^^
    Cảm ơn bạn nhiều.

    1. Hi bạn,
      Thật sự mình không có tài liệu cụ thể nào về vấn đề này cả. Bạn có thể search trên mạng về những thứ liên quan tới Web Extracting, Web Crawling… thì sẽ ra rất nhiều tài liệu về nó.
      Thân,

  3. cảm ơn anh…mà nếu có gì không hiểu thì mong anh giúp đỡ..
    mà tiện đây em hỏi lun…em viết đc đăng nhập vào 1 web site rồi dùng httpwebrequest, giờ em mún thực hiện các thao tác trên web ví dụ như click đến link nào đó hay nhấp vào button thì làm thế nào nữa hả anh…em mơ hồ wa…

  4. We’re a gaggle of volunteers and starting a brand new scheme in our community. Your web site offered us with useful information to work on. You’ve done
    an impressive task and our entire group will likely be thankful
    to you.

  5. My programmer is trying to persuade me to move to .

    net from PHP. I have always disliked the idea
    because of the costs. But he’s tryiong none the less. I’ve been using Movable-type on a number of websites for about a year and
    am anxious about switching to another platform.
    I have heard very good things about blogengine.net. Is there a way I can transfer
    all my wordpress content into it? Any kind of help
    would be greatly appreciated!

  6. Hello! I could have sworn I’ve been to your blog before but after browsing through some of the posts I realized it’s new to me.
    Anyhow, I’m definitely happy I found it and I’ll be bookmarking it and checking back often!

  7. A ơi bài viết tiếp theo đâu ạ?Sao e tìm mà k thấy?A bảo là “Trong bài sau, chúng ta sẽ cùng nhau tìm hiểu cách sử dụng phương pháp này để crawl dữ liệu từ các trang web.” , bài đó đâu ạ?

  8. It seems like you actually know quite a lot pertaining to this particular
    subject and that exhibits as a result of this amazing post, labeled “Gửi cc Request POST v GET trong C# | My power
    is my mind”. Thanks a lot ,Romeo

  9. Bài viết rất bổ ích và đã giúp mọi người hiểu ra nhiều vấn đề.
    Mình đã làm theo bài viết này để làm chức năng lấy thông tin vé máy bay từ 1 trang web khác và đến lệnh ” XDocument xmlDoc = XDocument.Load(reader);” thì gặp lỗi “the remote server returned an error: (500) internal server error.” và không biết phải sử lý thế nào

  10. Pingback: CNTT | Tuấn IT

Gửi phản hồi

Mời bạn điền thông tin vào ô dưới đây hoặc kích vào một biểu tượng để đăng nhập:

WordPress.com Logo

Bạn đang bình luận bằng tài khoản WordPress.com Log Out / Thay đổi )

Twitter picture

Bạn đang bình luận bằng tài khoản Twitter Log Out / Thay đổi )

Facebook photo

Bạn đang bình luận bằng tài khoản Facebook Log Out / Thay đổi )

Google+ photo

Bạn đang bình luận bằng tài khoản Google+ Log Out / Thay đổi )

Connecting to %s