HTTP Client

HTTP Client

Giao thức HTTP

HTTP – Hypertext Transfer Protocol (giao thức truyền dẫn siêu văn bản), là giao thức để truyền dữ liệu giữa các máy tính qua www (World Wide Web), với dữ liệu có thể là dạng text, file, ảnh, hoặc video.

HTTP được thiết kế để trao đổi dữ liệu giữa Client và Server trên nền TCP/IP, nó vận hành theo cơ chế yêu cầu/trả lời, stateless - không lưu trữ trạng thái. Trình duyệt Web chính là Client, và một máy chủ chứa Web Site là Server. Client sẽ kết nối tới Server, gởi dữ liệu đến server bao gồm các thông tin header. Server nhận được thông tin và căn cứ trên đó gởi phản hồi lại cho Client. Đồng thời đóng kết nối.

Một ví dụ điển hình là khi bạn gõ địa chỉ vào thanh địa chỉ của trình duyệt và nhấn Enter, thì ngay lập tức Web Client sẽ thực hiện việc gởi yêu cầu tới Web Server có địa chỉ mà bạn vừa gõ. Web Server sẽ trả lời bằng nội dung Web Site mà bạn cần xem.

Trong giao thức HTTP, việc thiết lập kết nối chỉ có thể xuất phát từ phía client ( lúc này có thể gọi là HTTP Client ). Khi client gửi yêu cầu, cùng với URL và payload ( dữ liệu muốn lấy ) tới server. Server ( HTTP Server ) lắng nghe mọi yêu cầu từ phía client và trả lời các yêu cầu ấy. Khi trả lời xong kết nối được chấm dứt.

Cách thức HTTP hoạt động
Hình 1. Cách thức HTTP hoạt động

Khi nhắc tới HTTP thì Hyperlink, hay URL (Uniform Resource Locator) là những khái niệm được thấy hàng ngày.

URL được dùng để định dạng địa chỉ Website, chứa các thông tin yêu cầu từ client và server dựa vào đó xử lý, cấu trúc của nó như hình:

URL
Hình 2. Cấu trúc 1 URL

Ví dụ bạn có thể gởi thông tin về nhiệt độ đến server thông qua đường dẫn: <a href="http://esp8266.vn/log.php?nhiet_do=30" class="bare">esp8266.vn/log.php?nhiet_do=30</a>

Cấu trúc 1 URL
|scheme  | host      |port |path            |query                |fragment|
 http:// server.com: 8080  /path/to/log.php ?nhiet_do=30&do_am=80 #test
  1. scheme xác định giao thức truyền tới server, nếu là https thì sẽ được mã hóa.

  2. host địa chỉ server.

  3. port port server dùng để phục vụ, nếu ko có thì mặc định là 80 cho web.

  4. path thông tin client muốn truy suất.

  5. query thông tin client muốn gởi lên.

  6. fragment thuộc tính này giúp browser đi đến vị trí của trang.

Với đường dẫn như trên, khi bạn gõ vào trình duyệt, thì trình duyệt sẽ thực hiện kết nối và gởi dữ liệu như sau.

GET /log.php?nhiet_do=30 HTTP/1.1
Host: esp8266.vn
User-Agent: curl/7.49.1
Accept: */*

Dữ liệu trả về:

HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
Transfer-Encoding: chunked
Connection: keep-alive

data
Trên linux, bạn có thể sử dụng curl để xem chi tiết dữ liệu raw truyền nhận, gõ lệnh curl -v <a href="http://esp8266.vn/log.php?nhiet_do=30" class="bare">esp8266.vn/log.php?nhiet_do=30</a> trên terminal

Giao thức HTTP định nghĩa một số phương thức (method) truyền đến Server:

  • GET là phương thức yêu cầu dữ liệu đơn giản và thường sử dụng nhất của HTTP. Phương thức GET yêu cầu server chỉ trả về dữ liệu bằng việc cung cấp các thông tin truy vấn trên URL, thông thường Server căn cứ vào thông tin truy vấn đó trả về dữ liệu mà không thay đổi nó. pathquery trong URL chứa thông tin truy vấn.

  • POST tương tự như GET, nhưng POST có thể gởi dữ liệu về Server.

  • PUT là phương thức yêu cầu tạo mới một dữ liệu, giống POST nhưng đánh dấu cho Server biết, nếu dữ liệu không tồn tại trong cơ sở dữ liệu thì tạo mới, hoặc sửa đổi nó.

  • DELETE Tương tự như GET, nhưng báo cho Server biết về việc xóa dữ liệu thông qua URL.

Các phương thức thông thường chỉ dùng GETPOST, các phương thức còn lại thường sử dụng trong API server (RESTful). Một số điểm khác biệt giữ POSTGET.

  • GET có thể bị cache (lưu trữ ở trình duyệt và sử dụng lại sau đó), nội dung request có thể lưu trữ ở lịch sử trình duyệt, có thể được đánh dấu (bookmark).

  • GET không nên sử dụng để gởi các dữ liệu nhạy cảm.

  • GET bị giới hạn độ lớn dữ liệu cần gởi.

  • GET chỉ nên dùng để lấy dữ liệu về.

  • POST không bị catch, không tồn tại dữ liệu gởi trong lịch sử trình duyệt, không thể đánh dấu (bookmark).

  • POST không giới hạn bởi độ lớn dữ liệu cần gởi.

HTTP Header & Status Code

Dữ liệu trả về bao giờ cũng có phần thông tin header với dòng đầu tiên chưa Status Code HTTP/1.1 200 OK có nghĩa là status code = 200, request được trả về phù hợp.
Theo sau đó là các cặp header chứa thông tin Server muốn trao đổi với Client, mà nếu là trình duyệt thì nó bị ẩn đi (người dùng bình thường không thể thấy). Các cặp header này định dạng theo kiểu name: value và kết thúc bằng ký tự xuống dòng không thấy bằng mắt thường (0x0D 0x0A hay \r\n).
Trong ví dụ trên, thông tin header Content-Type: text/html; charset=utf-8 báo cho trình duyệt biết rằng định dạng dữ liệu gởi về là dạng text, mã hóa utf-8. Transfer-Encoding: chunked chiều dài dữ liệu không được biết trước và gởi cho tới khi server đóng kết nối.

Một số HTTP status code thường thấy:

  • 1xx: Mã trạng thái thông tin. Bản chất của mã trạng thái này, chỉ để thông báo với client rằng request đã được chấp nhận. Các mã trạng thái thông tin này được quy định trong HTTP/1.1, còn phiên bản HTTP/1.0 hay trước đó thì không có, có thể bỏ qua phần mã trạng thái này. Các mã hay gặp:

    • 100 Continue: Thông báo cho Client biết là có thể gửi tiếp phần request còn lại nếu còn, kết thúc nếu đã hết. Nếu trong request POST, phần thân request lớn sẽ bị server từ chối và để giải quyết điều này thì client phải gửi Expect: 100-continue theo sau phần header ban đầu.

  • 2xx: Nhóm mã trạng thái này thông báo với Client rằng request đã được nhận, hiểu và xử lý thành công. Với một số mã thường thấy:

    • 200 OK: Thông báo cho Client biết là request đã gửi thành công. Có thể thấy mã trạng thái này trong các phương thức GET, HEAD, POST, TRACE.

    • 201 Created: Cho biết request đã xử lý thành công và tài nguyên đã được khởi tạo. Được sử dụng để xác nhận sự thành công của một request PUT hoặc POST.

    • 204 No Content: Thông báo không có phần thân message trong response.

  • 3xx: Nhóm mã trạng thái thông báo Client còn phải thực hiện thêm hành động để hoàn thành request. Mã trạng thái thường gặp trong nhóm:

    • 301 Moved Permanently: Thông báo tài nguyên được yêu cầu đã được chuyển hướng sang một URL mới và server sẽ gửi URL mới này trong response cho Client biết.

  • 4xx: Nhóm mã thông báo các lỗi từ phía Client. Được sử dụng khi server cho rằng phía Client đang xảy ra lỗi, với một request, hoặc tài nguyên không hợp lệ, hoặc một request không đúng. Các mã thông dụng:

    • 400 Bad Request: Thông báo request đã gửi là sai.

    • 401 Unauthorized: Chỉ ra rằng request cần được xác thực. Client có thể gửi lại request với header đã được xác thực. Trường hợp đã đính kèm header xác thực nhưng vẫn nhận được thông báo này tức là header xác thực chưa hợp lệ.

    • 403 Forbidden: Server từ chối quyền truy cập của Client.

    • 404 Not Found: Thông báo tài nguyên không hợp lệ và không tồn tại trên server.

    • 409 Conflict: Server không thể hoàn thành yêu cầu vì Client cố chỉnh sửa tài nguyên mới hơn so với timestamp của Client. Xung đột xảy ra chủ yếu trong các request PUT trong quá trình hợp tác chỉnh sửa tài nguyên.

  • 5xx: Nhóm lệnh thông báo server đang ở trong tình trạng lỗi hoặc không có khả năng thực hiện yêu cầu. Một số mã thường gặp:

    • 500 Internal Server Eror: Cho biết là không thể thực hiện request của Client.

    • 501 Not Implemented: Thông báo server không có phương thức được yêu cầu hoặc không có khả năng hổ trợ chức năng mà Client đã request.

    • 503 Service Unavailable: Xảy ra khi hệ thống của server đang bảo dưỡng hoặc quá tải.

JSON

JSON (JavaScript Object Notation) là 1 định dạng trao đổi dữ liệu để giúp việc đọc và viết dữ liệu trở nên dễ dàng hơn, máy tính cũng sẽ dễ phân tích và tạo ra JSON. Chúng là cơ sở dựa trên tập hợp của ngôn ngữ lập trình JavaScript. JSON là 1 định dạng kiểu text mà hoàn toàn độc lập với các ngôn ngữ hoàn chỉnh, thuộc họ hàng với các ngôn ngữ trong họ hàng của C, gồm có C, C++, C#, Java, JavaScript, Perl, Python, và nhiều ngôn ngữ khác. Những đặc tính đó đã tạo nên JSON 1 ngôn ngữ hoán vị dữ liệu lý tưởng.

JSON được xây dựng trên 2 cấu trúc:

  • Là tập hợp của các cặp tên và giá trị name-value. Trong những ngôn ngữ khác nhau, đây có thể là 1 object, record, struct, dictionary, hash table, keyed list hay associative array.

  • Là 1 tập hợp các giá trị đã được sắp xếp. Trong hầu hết các ngôn ngữ, dữ liệu này được xem như array, véc tơ, list hay sequence.
    Đây là 1 cấu trúc dữ liệu phổ dụng. Hầu như tất cả các ngôn ngữ lập trình hiện đại đều hổ trợ. Chúng tạo nên ý nghĩa của 1 định dạng hoán vị dữ liệu với các ngôn ngữ lập trình cũng đã được cơ sở hoá trên cấu trúc này.

Cú pháp

  • Dữ liệu nằm trong các cặp name/value

  • Các dữ liệu được ngăn cách bởi dấy phẩy ,

  • Các đối tượng (name/value) nằm giữa hai dấu ngoặc kép "

  • Tất cả các đối tượng nằm bên trong hai dấu ngoặc nhọn {}

  • Dữ liệu của JSON được viết theo từng cặp name/value. Một cặp name/value bao gồm trường name ( nằm trong hai dấu ngoặc kép ", theo sau là dấu hai chấm :, và sau cùng là trường value (cũng được nằm trong hai dấu ngoặc kép ". Ví dụ: "name":"John"

{
    "username" : "your-user-name",
    "email" : "your-email@email.com",
    "website" : "https://blog.unicloud.com.vn",
    "title" : "ESP8266 Tutorials"
}

Ứng dụng xem giá Bitcoin

Một ứng dụng đơn giản sử dụng giao thức HTTP để lấy tỉ giá Bitcoin (BTC)/USD từ các trang Web giao dịch, hiển thị lên màn hình OLED.

Chúng ta có rất nhiều nguồn lấy tỉ giá, một trong số đó là www.cryptocompare.com/. Với tài liệu được cung cấp, và nhu cầu là chỉ lấy tỉ giá Bitcoin/USD, chúng ta chỉ cần ESP8266 gởi 1 HTTP Request đến min-api.cryptocompare.com/data/price?fsym=BTC&tsyms=USD thì sẽ nhận được một chuỗi JSON dạng như:

{"USD":4731.44}

và giá trị của trường USD chính là giá trị chúng ta muốn hiển thị.

Đa số các dịch vụ Web hiện nay đều sử dụng giao thức bảo mật HTTPS, về cơ bản nó cũng là HTTP, nhưng quá trình truyền nhận được mã hóa dữ liệu, thực hiện xác thực trước khi gửi giữa Client và Server.

Khi dùng HTTPS, chúng ta cần cung cấp SHA1 Fingerpint để Client có thể xác thực server. Bạn có thể dùng trình duyệt để truy cập trước để lấy. Nếu là Chrome, sau khi truy cập vào địa chỉ min-api.cryptocompare.com/data/price?fsym=BTC&tsyms=USD, Nhấn Ctrl+Shift+I (Shift + ⌘ + I với MacOS) và đi đến Security > View Certificate > Details > Thumbprint. Bạn sẽ thấy hình như bên dưới, và copy nó.

HTTPS Finger print
Hình 3. HTTPS Fingerprint

Đây là đoạn Code lấy giá Bitcoin, cứ mỗi 5 giây, ESP8266 sẽ kết nối đến Cryptocompare server để lấy thông tin và hiển thị lên OLED.

#include <ESP8266WiFi.h>
#include <ESP8266HTTPClient.h>
#include <ArduinoJson.h> //https://github.com/bblanchon/ArduinoJson
#include "SSD1306.h" //https://github.com/squix78/esp8266-oled-ssd1306

const char* ssid = "your-ssid";
const char* password = "your-password";
SSD1306  display(0x3c, 4, 5);
/* xem thêm https://www.cryptocompare.com/api/ */
const char* host = "https://min-api.cryptocompare.com/data/price?fsym=BTC&tsyms=USD";
/*SHA1 fingerprint*/
const char* fingerprint = "61 DE E9 FF BB 6B AD AA E4 9A 38 95 DC EC 74 2C 61 4B 7D 07";

void getBitcoin()
{
  HTTPClient http;
  Serial.print("connecting to ");
  Serial.println(host);

  http.begin(host, fingerprint);
  int httpCode = http.GET();
  if (httpCode == HTTP_CODE_OK) {
    String payload = http.getString();
    Serial.println(payload);
    StaticJsonBuffer<512> jsonBuffer;
    JsonObject& root = jsonBuffer.parseObject(payload);
    if (!root.success()) {
      Serial.println("parseObject() failed");
      return;
    }

    double priceUSD = root["USD"];
    display.clear();
    display.drawString(0, 0, "Bitcoin price");
    display.drawString(0, 18, String(priceUSD));
    display.display();
    Serial.println(priceUSD);
  }
  http.end();
}

void setup() {
  Serial.begin(115200);
  display.init();
  display.clear();
  display.setFont(ArialMT_Plain_16);
  display.drawString(0, 0, "Connecting to");
  display.drawString(0, 18, ssid);
  display.display();
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  display.clear();
  display.drawString(0, 0, "Connected");
  display.display();
}

void loop() {
  if (WiFi.status() == WL_CONNECTED) {
    getBitcoin();
  }
  delay(5000);
}

Thay đổi SSID và Password bạn đang sử dụng. Nạp chương trình cho board NodeMCU và xem kết quả hiển trị trên màn hình OLED.

  • Chờ đợi board NodeMCU kết nối với WiFi.

  • Sau khi kết nối WiFi thành công, cứ mỗi 5 giây, thiết bị sẽ get giá Bitcoin 1 lần và hiển thị ra màn hình OLED.

Trả lời

Email của bạn sẽ không được hiển thị công khai. Các trường bắt buộc được đánh dấu *