Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Debugging Ajax Calls

Debugging Ajax Calls

An introduction to debugging Ajax calls with cURL and the Chrome Network Tools.

These slides were used to create these videos:

https://www.youtube.com/watch?v=9JzQPrGaMhw&t=73s
https://www.youtube.com/watch?v=RcrW7PCzx3Q

A333869fa8934ab32efb4e78e7c1dff1?s=128

Toby Ho

July 17, 2017
Tweet

More Decks by Toby Ho

Other Decks in Programming

Transcript

  1. Debugging Ajax Calls

  2. Overview • HTTP request/response • Chrome Network Tools • Filtering

    request/responses • Request/response details • Copying and replaying • Inspecting Errors • XHR breakpoints • What are we doing?
  3. Why?

  4. A HTTP request/response $ curl http://chad.is/ -v Curl (sometimes spelled

    cURL) is a command-line based tool for making HTTP requests
  5. A HTTP request/response $ curl http://chad.is/ -v * Hostname was

    NOT found in DNS cache * Trying 192.30.252.153... * Connected to chad.is (192.30.252.153) port 80 (#0) > GET / HTTP/1.1 > User-Agent: curl/7.37.1 > Host: chad.is > Accept: */* > < HTTP/1.1 200 OK * Server GitHub.com is not blacklisted < Server: GitHub.com < Date: Sun, 16 Jul 2017 06:05:39 GMT < Content-Type: text/html; charset=utf-8 < Content-Length: 2303 < Last-Modified: Sat, 08 Jul 2017 09:09:13 GMT < Access-Control-Allow-Origin: * < Expires: Sun, 16 Jul 2017 06:15:39 GMT < Cache-Control: max-age=600 < Accept-Ranges: bytes < X-GitHub-Request-Id: 5FE0:0DE8:A7B67D:EC9F7F:596B0233 < <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta name="description" content="Chad Mazzola lives in Stockholm, Sweden."> <meta name="viewport" content="width=device-width; initial-scale=1.0"> <title>Chad Mazzola</title> <link href="https://fonts.googleapis.com/css?family=Karla:400,400i,700,700i" rel="stylesheet"> <link rel="stylesheet" href="/stylesheets/application.css"> <link href="/feeds/articles.xml" rel="alternate" title="RSS feed" type="application/atom+xml"> <script type="text/javascript"> var _gaq = _gaq || []; …
  6. The Request $ curl http://chad.is/ -v * Hostname was NOT

    found in DNS cache * Trying 192.30.252.153... * Connected to chad.is (192.30.252.153) port 80 (#0) > GET / HTTP/1.1 > User-Agent: curl/7.37.1 > Host: chad.is > Accept: */* > < HTTP/1.1 200 OK * Server GitHub.com is not blacklisted < Server: GitHub.com < Date: Sun, 16 Jul 2017 06:05:39 GMT < Content-Type: text/html; charset=utf-8 < Content-Length: 2303 < Last-Modified: Sat, 08 Jul 2017 09:09:13 GMT < Access-Control-Allow-Origin: * < Expires: Sun, 16 Jul 2017 06:15:39 GMT < Cache-Control: max-age=600 < Accept-Ranges: bytes < X-GitHub-Request-Id: 5FE0:0DE8:A7B67D:EC9F7F:596B0233 < <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta name="description" content="Chad Mazzola lives in Stockholm, Sweden."> <meta name="viewport" content="width=device-width; initial-scale=1.0"> <title>Chad Mazzola</title> <link href="https://fonts.googleapis.com/css?family=Karla:400,400i,700,700i" rel="stylesheet"> <link rel="stylesheet" href="/stylesheets/application.css"> <link href="/feeds/articles.xml" rel="alternate" title="RSS feed" type="application/atom+xml"> <script type="text/javascript"> var _gaq = _gaq || []; …
  7. The Response $ curl http://chad.is/ -v * Hostname was NOT

    found in DNS cache * Trying 192.30.252.153... * Connected to chad.is (192.30.252.153) port 80 (#0) > GET / HTTP/1.1 > User-Agent: curl/7.37.1 > Host: chad.is > Accept: */* > < HTTP/1.1 200 OK * Server GitHub.com is not blacklisted < Server: GitHub.com < Date: Sun, 16 Jul 2017 06:05:39 GMT < Content-Type: text/html; charset=utf-8 < Content-Length: 2303 < Last-Modified: Sat, 08 Jul 2017 09:09:13 GMT < Access-Control-Allow-Origin: * < Expires: Sun, 16 Jul 2017 06:15:39 GMT < Cache-Control: max-age=600 < Accept-Ranges: bytes < X-GitHub-Request-Id: 5FE0:0DE8:A7B67D:EC9F7F:596B0233 < <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta name="description" content="Chad Mazzola lives in Stockholm, Sweden."> <meta name="viewport" content="width=device-width; initial-scale=1.0"> <title>Chad Mazzola</title> <link href="https://fonts.googleapis.com/css?family=Karla:400,400i,700,700i" rel="stylesheet"> <link rel="stylesheet" href="/stylesheets/application.css"> <link href="/feeds/articles.xml" rel="alternate" title="RSS feed" type="application/atom+xml"> <script type="text/javascript"> var _gaq = _gaq || []; …
  8. The Request: In Detail GET / HTTP/1.1 User-Agent: curl/7.37.1 Host:

    chad.is Accept: */*
  9. The Request: In Detail GET / HTTP/1.1 User-Agent: curl/7.37.1 Host:

    chad.is Accept: */* Method
  10. The Request: In Detail GET / HTTP/1.1 User-Agent: curl/7.37.1 Host:

    chad.is Accept: */* Path (a.k.a the URI)
  11. The Request: In Detail GET / HTTP/1.1 User-Agent: curl/7.37.1 Host:

    chad.is Accept: */* HTTP version
  12. The Request: In Detail GET / HTTP/1.1 User-Agent: curl/7.37.1 Host:

    chad.is Accept: */* HTTP Headers
  13. The Request: In Detail GET / HTTP/1.1 User-Agent: curl/7.37.1 Host:

    chad.is Accept: */* Blank line
  14. The Response: In Detail HTTP/1.1 200 OK Server: GitHub.com Date:

    Sun, 16 Jul 2017 06:05:39 GMT Content-Type: text/html; charset=utf-8 Content-Length: 2303 Last-Modified: Sat, 08 Jul 2017 09:09:13 GMT Access-Control-Allow-Origin: * Expires: Sun, 16 Jul 2017 06:15:39 GMT Cache-Control: max-age=600 Accept-Ranges: bytes X-GitHub-Request-Id: 5FE0:0DE8:A7B67D:EC9F7F:596B0233 <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta name="description" content="Chad Mazzola lives in Stockholm, Sweden."> <meta name="viewport" content="width=device-width; initial-scale=1.0"> <title>Chad Mazzola</title> <link href="https://fonts.googleapis.com/css?family=Karla:400,400i,700,700i" rel="stylesheet"> <link rel="stylesheet" href="/stylesheets/application.css"> <link href="/feeds/articles.xml" rel="alternate" title="RSS feed" type="application/atom+xml"> <script type="text/javascript"> var _gaq = _gaq || []; …
  15. The Response: In Detail HTTP/1.1 200 OK Server: GitHub.com Date:

    Sun, 16 Jul 2017 06:05:39 GMT Content-Type: text/html; charset=utf-8 Content-Length: 2303 Last-Modified: Sat, 08 Jul 2017 09:09:13 GMT Access-Control-Allow-Origin: * Expires: Sun, 16 Jul 2017 06:15:39 GMT Cache-Control: max-age=600 Accept-Ranges: bytes X-GitHub-Request-Id: 5FE0:0DE8:A7B67D:EC9F7F:596B0233 <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta name="description" content="Chad Mazzola lives in Stockholm, Sweden."> <meta name="viewport" content="width=device-width; initial-scale=1.0"> <title>Chad Mazzola</title> <link href="https://fonts.googleapis.com/css?family=Karla:400,400i,700,700i" rel="stylesheet"> <link rel="stylesheet" href="/stylesheets/application.css"> <link href="/feeds/articles.xml" rel="alternate" title="RSS feed" type="application/atom+xml"> <script type="text/javascript"> var _gaq = _gaq || []; … HTTP version
  16. The Response: In Detail HTTP/1.1 200 OK Server: GitHub.com Date:

    Sun, 16 Jul 2017 06:05:39 GMT Content-Type: text/html; charset=utf-8 Content-Length: 2303 Last-Modified: Sat, 08 Jul 2017 09:09:13 GMT Access-Control-Allow-Origin: * Expires: Sun, 16 Jul 2017 06:15:39 GMT Cache-Control: max-age=600 Accept-Ranges: bytes X-GitHub-Request-Id: 5FE0:0DE8:A7B67D:EC9F7F:596B0233 <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta name="description" content="Chad Mazzola lives in Stockholm, Sweden."> <meta name="viewport" content="width=device-width; initial-scale=1.0"> <title>Chad Mazzola</title> <link href="https://fonts.googleapis.com/css?family=Karla:400,400i,700,700i" rel="stylesheet"> <link rel="stylesheet" href="/stylesheets/application.css"> <link href="/feeds/articles.xml" rel="alternate" title="RSS feed" type="application/atom+xml"> <script type="text/javascript"> var _gaq = _gaq || []; … Status Code and message
  17. Response: The Status Code

  18. Response: The Status Code 1xx Informational responses. 2xx Success. 3xx

    Redirection. 4xx Client errors. 5xx Server errors.
  19. Success Response Codes 200 - Ok 201 - (Successfully) created

    202 - Accepted more…
  20. Error Status Codes 400 - Bad Request (it was your

    fault) 401 - Unauthorized 403 - Forbidden 404 - Not Found 405 - Method Not Allowed (maybe you are using GET where you are supposed to use POST) 500 - Internal Server Error (it was our fault) 501 - Not Implemented 502 - Bad Gateway (you are accessing this through a proxy server, and the proxy server got an error from the original server) more…
  21. The Response: In Detail HTTP/1.1 200 OK Server: GitHub.com Date:

    Sun, 16 Jul 2017 06:05:39 GMT Content-Type: text/html; charset=utf-8 Content-Length: 2303 Last-Modified: Sat, 08 Jul 2017 09:09:13 GMT Access-Control-Allow-Origin: * Expires: Sun, 16 Jul 2017 06:15:39 GMT Cache-Control: max-age=600 Accept-Ranges: bytes X-GitHub-Request-Id: 5FE0:0DE8:A7B67D:EC9F7F:596B0233 <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta name="description" content="Chad Mazzola lives in Stockholm, Sweden."> <meta name="viewport" content="width=device-width; initial-scale=1.0"> <title>Chad Mazzola</title> <link href="https://fonts.googleapis.com/css?family=Karla:400,400i,700,700i" rel="stylesheet"> <link rel="stylesheet" href="/stylesheets/application.css"> <link href="/feeds/articles.xml" rel="alternate" title="RSS feed" type="application/atom+xml"> <script type="text/javascript"> var _gaq = _gaq || []; … Headers
  22. The Response: In Detail HTTP/1.1 200 OK Server: GitHub.com Date:

    Sun, 16 Jul 2017 06:05:39 GMT Content-Type: text/html; charset=utf-8 Content-Length: 2303 Last-Modified: Sat, 08 Jul 2017 09:09:13 GMT Access-Control-Allow-Origin: * Expires: Sun, 16 Jul 2017 06:15:39 GMT Cache-Control: max-age=600 Accept-Ranges: bytes X-GitHub-Request-Id: 5FE0:0DE8:A7B67D:EC9F7F:596B0233 <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta name="description" content="Chad Mazzola lives in Stockholm, Sweden."> <meta name="viewport" content="width=device-width; initial-scale=1.0"> <title>Chad Mazzola</title> <link href="https://fonts.googleapis.com/css?family=Karla:400,400i,700,700i" rel="stylesheet"> <link rel="stylesheet" href="/stylesheets/application.css"> <link href="/feeds/articles.xml" rel="alternate" title="RSS feed" type="application/atom+xml"> <script type="text/javascript"> var _gaq = _gaq || []; … Blank line
  23. The Response: In Detail HTTP/1.1 200 OK Server: GitHub.com Date:

    Sun, 16 Jul 2017 06:05:39 GMT Content-Type: text/html; charset=utf-8 Content-Length: 2303 Last-Modified: Sat, 08 Jul 2017 09:09:13 GMT Access-Control-Allow-Origin: * Expires: Sun, 16 Jul 2017 06:15:39 GMT Cache-Control: max-age=600 Accept-Ranges: bytes X-GitHub-Request-Id: 5FE0:0DE8:A7B67D:EC9F7F:596B0233 <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta name="description" content="Chad Mazzola lives in Stockholm, Sweden."> <meta name="viewport" content="width=device-width; initial-scale=1.0"> <title>Chad Mazzola</title> <link href="https://fonts.googleapis.com/css?family=Karla:400,400i,700,700i" rel="stylesheet"> <link rel="stylesheet" href="/stylesheets/application.css"> <link href="/feeds/articles.xml" rel="alternate" title="RSS feed" type="application/atom+xml"> <script type="text/javascript"> var _gaq = _gaq || []; … Body
  24. The Response: In Detail HTTP/1.1 200 OK Server: GitHub.com Date:

    Sun, 16 Jul 2017 06:05:39 GMT Content-Type: text/html; charset=utf-8 Content-Length: 2303 Last-Modified: Sat, 08 Jul 2017 09:09:13 GMT Access-Control-Allow-Origin: * Expires: Sun, 16 Jul 2017 06:15:39 GMT Cache-Control: max-age=600 Accept-Ranges: bytes X-GitHub-Request-Id: 5FE0:0DE8:A7B67D:EC9F7F:596B0233 <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta name="description" content="Chad Mazzola lives in Stockholm, Sweden."> <meta name="viewport" content="width=device-width; initial-scale=1.0"> <title>Chad Mazzola</title> <link href="https://fonts.googleapis.com/css?family=Karla:400,400i,700,700i" rel="stylesheet"> <link rel="stylesheet" href="/stylesheets/application.css"> <link href="/feeds/articles.xml" rel="alternate" title="RSS feed" type="application/atom+xml"> <script type="text/javascript"> var _gaq = _gaq || []; … Body More content omitted for brevity
  25. The Response: In Detail HTTP/1.1 200 OK Server: GitHub.com Date:

    Sun, 16 Jul 2017 06:05:39 GMT Content-Type: text/html; charset=utf-8 Content-Length: 2303 Last-Modified: Sat, 08 Jul 2017 09:09:13 GMT Access-Control-Allow-Origin: * Expires: Sun, 16 Jul 2017 06:15:39 GMT Cache-Control: max-age=600 Accept-Ranges: bytes X-GitHub-Request-Id: 5FE0:0DE8:A7B67D:EC9F7F:596B0233 <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta name="description" content="Chad Mazzola lives in Stockholm, Sweden."> <meta name="viewport" content="width=device-width; initial-scale=1.0"> <title>Chad Mazzola</title> <link href="https://fonts.googleapis.com/css?family=Karla:400,400i,700,700i" rel="stylesheet"> <link rel="stylesheet" href="/stylesheets/application.css"> <link href="/feeds/articles.xml" rel="alternate" title="RSS feed" type="application/atom+xml"> <script type="text/javascript"> var _gaq = _gaq || []; … This is HTML Mime Type for HTML
  26. Response Types • HTML - text/html • CSS - text/css

    • JavaScript - text/javascript • JSON - application/json
  27. Now you try!! $ curl SOME_URL_YOU_KNOW -v

  28. Chrome Network Tools a.k.a Chrome Dev Tools Network Panel

  29. None
  30. None
  31. The Network Tab

  32. Close the console to get more real estate

  33. None
  34. Red means it’s recording

  35. If you see this, there’s been no request/responses recorded

  36. Perform an action on the page that triggers a new

    request
  37. Refresh the page and record all the requests issued as

    result of loading the page Click to reload
  38. These are the requests issued to load the page Summary

  39. Waterfall Graph

  40. Waterfall Graph

  41. Waterfall Graph DOM Content Loaded

  42. Waterfall Graph Visual snapshots

  43. Waterfall Graph Toggle snapshots

  44. Now you try! Open a web site of your choice

    and look at all requests issued in order to load the page, and the waterfall graph.
  45. Example: Weather App

  46. None
  47. The Filter Panel

  48. Filter Panel: Search box Filter requests by URL path

  49. Filter Panel: Search box Optionally use regex

  50. Filter Panel: Filter by type

  51. Filter Panel: Filter by type Showing only XHR (Ajax) requests

  52. Drill Down: Request/Response Details Selecting a request shows you more

    details
  53. Request/Response Details: Headers tab URL, Method, Status Code, etc

  54. Request/Response Details: Headers tab All response headers

  55. Request/Response Details: Headers tab All request headers

  56. Request/Response Details: Preview

  57. Request/Response Details: Response

  58. Request/Response Details: Timing

  59. Copy Request URL Copy the URL of the request

  60. Open in New Tab Open the URL of the request

    in a new tab. Great for GET requests
  61. Copy as cURL Copy a cURL command to your clipboard

    which you can use in the terminal!!!
  62. Copy as cURL

  63. Copy as cURL Will preserve all headers/cookies so will work

    even when authentication is required by the backend
  64. Replay the Request Issue this same exact request

  65. Replay the Request The new duplicate request

  66. Now you try!! • Open a web site / web

    app of your choice • Look at all request/responses • Use the filter panel to look at only the Ajax request/responses • Use the text filter to view only the requests with a particular substring in the URL • Select a particular request/response and inspect the, headers tab, preview tab, response tab, and the timing tab • Re-issue the request by copying its URL, a cURL command, or by replaying the request
  67. Errors

  68. I am going to induce an error by putting in

    a bogus city name
  69. A request that came back with a 404 (not found)

    error
  70. Coming from the Console Tab When you encounter an error

    response, you will see it in your console as well, click on it to switch to the network panel
  71. The clicked request will be highlighted briefly

  72. Let’s select it to see more detail We sent this

    in the q parameter
  73. This is the error message from the backend

  74. Let’s run the request using cURL

  75. Pretend you just recognized this as the problem, fix it

    in this command and test again
  76. Now we have good data

  77. XHR (Ajax) Breakpoints Use if you don’t know and want

    to find out what line of code initiated a particular request
  78. None
  79. First come up with a substring to filter down to

    just the request(s) you are interested in
  80. Add an XHR breakpoint

  81. Type in substring to match on, hit enter

  82. Now induce the request again, in my case, I had

    to reload the page. Now the debugger has paused on the line that induces the request
  83. Being dropped into jQuery’s source code might seem intimidating, but

    actually, we can relate this to the application code by looking down in the call stack
  84. First frame that came from app.js

  85. First frame that came from app.js. Click on it!

  86. Boom! This is the line that initiated the request

  87. Because we are still in the debugger session, we can

    see the variables in the frame, such as city, which has the value “Atlanta”
  88. Now you try!! • Induce an error - 4xx or

    5xx (by changing the frontend or backend code) • Set up and test out an XHR breakpoint
  89. What are we actually doing?

  90. Debugging: Isolate the Problem • Which request caused the problem?

    • Is it caused by • front-end code • error in the way the request is sent • both the request and response look good, so problem must be with elsewhere in the front-end • back-end code
  91. If you know which request is the relevant or problematic

    one
  92. Look at the response status code for that request

  93. Look at the Response or Preview tab in request/response details

  94. Look at the Headers tab in request/response details. Optionally, copy

    the cURL command and try to change the command’s URL to fix the request until the response is good
  95. If you don’t know what’s the problematic request • Is

    there a request with an error response? Look in the console or look through the list of requests in the Network Tools • Use your knowledge of the code. Which request is supposed to retrieve the data that’s not being displayed correctly, or cause a change to the database correctly?
  96. Performance Tuning • Look at the waterfall graph • Look

    at the response times - are individual responses taking a long time? • Look at the number of requests - are there many requests? the fewer the better (Browsers can only send 3-6 requests in parallel) • What are the requests doing? Can we eliminate some of them by batch multiple requests into one
  97. Now you try!! • Think of a problem with your

    app that could benefit from using the network tools • Use Chrome Network Tools to isolate the problem