浏览器发送请求的方法

浏览器发送请求的方法

最初的 form 表单提交

enctype, 提交数据的格式,用 enctype 将数据发送到服务端时指定的编码类型。

  • application/x-www-form-urlencoded:

    node中的http.createServer方法中,通过监听reqdata数据,可以接受到相关传参数据。

    对于application/x-www-form-urlencoded传参方式,可以直接获取到传参xx=xxx&xx=xxx

    req.on('data', (chunk) => {
      buffer += chunk.toString('utf8');
    });
    
  • multipart/form-data

    而对于multipart/form-data,则获取的数据不同,会读取到content-type后边的boundary数据

    比如 'content-type': 'multipart/form-data; boundary=----WebKitFormBoundaryxxxxxxxxxxxx',,

    此时读取的到的为------WebKitFormBoundaryxxxxxxxxxxxx,可以使用类似multiparty进行解析。

    const form = new multiparty.Form();
    form.parse(req, function (err, fields, files) {
      // fields 是通过formData传入的字段跟值
      // files 则是文件
    });
    
  • text/plain

    纯文本格式

表单开始提交,浏览器就会刷新页面,然后在新页面里告诉你操作是成功了还是失败了。如果不幸由于网络太慢或者其他原因,就会得到一个 404 页面。

ajax 的出现

AJAX 是一种在无需重新加载整个网页的情况下,能够更新部分网页的技术。

在现代浏览器上写 AJAX 主要依靠 XMLHttpRequest 对象

AJAX 请求是异步执行的,也就是说,要通过回调函数获得响应

var request = new XMLHttpRequest(); // 新建XMLHttpRequest对象

request.onreadystatechange = function () {
  // 状态发生变化时,函数被回调
  if (request.readyState === 4) {
    // 成功完成
    // 判断响应结果:
    if (request.status === 200) {
      // 成功,通过responseText拿到响应的文本:
      console.log(request.responseText);
    } else {
      // 失败,根据响应码判断失败原因:
      console.log(request.status);
    }
  } else {
    // HTTP请求还在继续...
  }
};

// 发送请求:
request.open('GET', '/api/xxxx');
request.send();

XMLHttpRequest

XMLHttpRequestXHR)对象用于与服务器交互。通过 XMLHttpRequest 可以在不刷新页面的情况下请求特定 URL,获取数据。这允许网页在不影响用户操作的情况下,更新页面的局部内容。

readyState

XMLHttpRequest.readyState 属性返回一个 XMLHttpRequest 代理当前所处的状态。

  • 0 (UNSENT)
    XMLHttpRequest 代理已被创建,但尚未调用 open() 方法。
  • 1 (OPENED)
    open() 方法已经被触发。在这个状态中,可以通过 setRequestHeader() 方法来设置请求的头部,可以调用 send() 方法来发起请求。
  • 2 (HEADERS_RECEIVED)
    send() 方法已经被调用,响应头也已经被接收。
  • 3 (LOADING)
    响应体部分正在被接收。如果 responseType 属性是“text”或空字符串,responseText 将会在载入的过程中拥有部分响应数据。
  • 4 (DONE)
    请求操作已经完成。这意味着数据传输已经彻底完成或失败。
var xhr = new XMLHttpRequest();
console.log('UNSENT', xhr.readyState); // readyState 为 0

xhr.open('GET', '/api', true);
console.log('OPENED', xhr.readyState); // readyState 为 1

xhr.onprogress = function () {
  console.log('LOADING', xhr.readyState); // readyState 为 3
};

xhr.onload = function () {
  console.log('DONE', xhr.readyState); // readyState 为 4
};

xhr.send(null);

progress 事件监听如果是同步请求(open方法的第三个参数为false)则不会触发。

onreadystatechange

readyState属性变化时,会触发这个方法。

// 在onreadystatechange方法中判断readyState的状态码
request.onreadystatechange = function () {
  if (request.readyState === 4) {
    if (request.status === 200) {
      // ....
    }
  }
};
response

response 返回响应文本。返回的类型为 ArrayBufferBlobDocumentJavaScript Object 或字符串中的一个。这取决于请求的 responseType 属性。

responseType

用于指定响应中包含的数据类型。如果responseType的值为一个空字符串,那么text为默认值,response就是一个字符串。

responseText

返回的纯文本的值。

只有当readyState的值为 4 及status为 200 时,responseText才是完成的返回数据。

responseURL

返回当前请求的url,如果是经过多次重定向的那么值为最终的url.

XMLHttpRequestfetch内部对重定向做了处理,不会重新建立连接

responseXML

当响应头中的content-typetext/xml或者直接设置responseTypedocument,响应响应则会按照text/xml进行解析。

status

响应状态码,遵循标准响应码规范。

HTTP 响应状态码用来表明特定 HTTP 请求是否成功完成。 响应被归为以下五大类:

  1. 信息响应 (100–199)
  2. 成功响应 (200–299)
  3. 重定向消息 (300–399)
  4. 客户端错误响应 (400–499)
  5. 服务端错误响应 (500–599)

规范

statusText

响应状态码对应的文本信息。如果服务器未明确指定一个状态文本信息,则statusText的值将会被自动赋值为"OK"

timeout

无符号长整型数,代表着一个请求在被自动终止前所消耗的毫秒数。默认值为 0,意味着没有超时。超时并不应该用在同步 XMLHttpRequests 请求中,否则将会抛出一个 InvalidAccessError 类型的错误。当超时发生, timeout 事件将会被触发。

var xhr = new XMLHttpRequest();
xhr.open('GET', '/server', true);

xhr.timeout = 2000; // 超时时间,单位是毫秒

xhr.onload = function () {
  // 请求完成。在此进行处理。
};

xhr.ontimeout = function (e) {
  // XMLHttpRequest 超时。在此做某事。
};

xhr.send(null);
upload

用来表示上传的进度

withCredentials

是否会携带用户凭证(cookie)。

默认false,即不携带,在httprequest中不传cookie字段。

如果在设置为true,那么服务端的响应头也需要设置Access-Control-Allow-Credentialstrue,否则也不能正常访问(CORS错误)。

通过设置withCredentialstrue可以获取第三方的cookies,如果以cookie作为凭证,容易造成CORS攻击。

可能攻击的方式:

  1. 如果以cookie为凭证且指定Access-Control-Allow-Origin*,那么使用iframe嵌套直接伪造请求就可以实现cors攻击。
  2. 如果以cookie为凭证但是指定Access-Control-Allow-Origin为对应的域名,可以在控制台中直接发送请求进行攻击。
abort

如果请求已被发出,则立刻中止请求。

当一个请求被终止,它的 readyState 将被置为 XMLHttpRequest.UNSENT (0),并且请求的 status 置为 0

即使请求中断了,但是服务端仍然接受到请求,只不过浏览器拒收

一个请求如果还没响应,这时候再发请求那么xmlHttpRequest内部会自动将前一个请求进行中断之后发送最新的请求。

open

初始化一个新创建的请求,或重新初始化一个请求。

xhrReq.open(method, url, async, user, password);
  • method: 使用的 HTTP 方法,比如 GETPOSTPUTDELETE、等。对于非 HTTP(S) URL 被忽略。
  • url: 请求的 URL
  • async: 是否异步执行操作,默认为 true。如果值为 falsesend() 方法直到收到答复前不会返回。如果 true,已完成事务的通知可供事件监听器使用。如果 multipart 属性为 true 则这个必须为 true,否则将引发异常。
  • user: 可选的用户名用于认证用途;默认为 null
  • password: 可选的密码用于认证用途,默认为 null
send

发送请求,如果请求类型为异步请求,send()方法的返回值会立即返回.

getAllResponseHeaders

返回响应的header信息(String 类型),以CRLF分割.如果没有接收到响应头,则返回null
通过以下方式可以进行解析对象:

const parsedHeaders = {};
request
  .getAllResponseHeaders()
  .split('\n')
  .forEach((item) => {
    const i = item.indexOf(':');
    const key = item.substr(0, i).replace(/^\s*/, '').replace(/\s*$/, '');
    const val = item.substr(i + 1);
    if (key) {
      if (key === 'set-cookie') {
        parsedHeaders[key] = (parsedHeaders[key] ? parsedHeaders[key] : []).concat([val]);
      } else {
        parsedHeaders[key] = parsedHeaders[key] ? parsedHeaders[key] + ', ' + val : val;
      }
    }
  });
getResponseHeader

获取某个header属性的值,name参数为需要获取属性值的key.如果header对象不存在此属性或者获取header对象失败,则返回null.

setRequestHeader

设置HTTP请求头.此方法需要在open()之后和send()之前执行.如果设置了不被支持的属性,请求可能会报错。

XMLHttpRequest.setRequestHeader(key, value);

对于FormDataBlobfile这个数据,不需要手动设置Content-Type,浏览器会自动进行设置。

监听事件

可通过addEventListener或者on + 事件名进行监听XMLHttpRequest实例

  • abort
  • error
  • load
  • loadstart
  • loadend
  • progress
  • timeout

fetch

XMLHttpRequest外,浏览器还提供了一个更简单的方法fetch

fetch接受两个参数:

  • input: 可以是请求URL,也可以是一个Request对象(实验中)。

  • init: 一个配置项对象

    • method: 请求方法
    • headers: 请求头.
      如果是post请求,需要传content-type进行标识

      formData格式数据不需要传content-type,浏览器会进行处理。

      Blob数据如果不传content-type,会报错。

      StringObject格式数据默认content-typetext/plain;charset=UTF-8Object数据在传递时会被转换成String格式(调用toString方法变成[object Object], 需要使用JSON.stringify方法转换成string)。

    • body: 请求的 body 信息。注意 GETHEAD 方法的请求不能包含 body 信息, 不然会报错
    • mode: 请求方式(在浏览器头中的sec-fetch-mode字段), 如corsno-cors 或者 same-origin
      默认cors

      no-cors,如果是跨域,不会报错,浏览器中的请求其实已经成功,但是fetch会对response进行拦截,返回的promise是请求失败的。请求方法只限于 GETPOSTHEAD,并且只能使用有限的几个简单标头,不能添加跨域的复杂标头,相当于提交表单所能发出的请求。

      same-origin,跨域会报错。

    • credentials: 请求的 credentials,如 omitsame-origin 或者 include
      same-origin:默认值,同源请求时发送 Cookie,跨域请求时不发送。

      include:不管同源请求,还是跨域请求,一律发送 Cookie

      omit:一律不发送。

    • cache: 请求的 cache 模式:defaultno-storereloadno-cacheforce-cache 或者 only-if-cached

      default:默认值,先在缓存里面寻找匹配的请求。

      no-store:直接请求远程服务器,并且不更新缓存。

      reload:直接请求远程服务器,并且更新缓存。

      no-cache:将服务器资源跟本地缓存进行比较,有新的版本才使用服务器资源,否则使用缓存。

      force-cache:缓存优先,只有不存在缓存的情况下,才请求远程服务器。

      only-if-cached:只检查缓存,如果缓存里面不存在,将返回 504 错误。

    • redirect: 可用的 redirect 模式:follow (自动重定向), error (如果产生重定向将自动终止并且抛出一个错误),或者 manual (手动处理重定向)。在 Chrome 中默认使用 followChrome 47 之前的默认值是 manual)。

      follow默认值,fetch()跟随 HTTP 跳转

      error,当请求返回是重定向时,会报错

      manual, fetch()不跟随 HTTP 跳转,response.url属性会指向当前 URL

    • referrer: 一个 USVString 可以是 no-referrerclient 或一个 URL。默认是 client
      设置这个值(xxx),那么请求中的refer字段值为host + xxx
      这个属性可以为任意字符串,也可以设为空字符串(即不发送 referer 标头)。
    • referrerPolicy: 指定了 HTTP 头部 referer 字段的值。可能为以下值之一:no-referrerno-referrer-when-downgradeoriginorigin-when-cross-originunsafe-url

      no-referrer不携带referer字段

      no-referrer-when-downgrade:默认值,总是发送Referer标头,除非从 HTTPS 页面请求 HTTP 资源时不发送

      originreferer标头只包含域名,不包括路径

      origin-when-cross-origin:同源请求Referer标头包含完整的路径,跨域请求只包含域名。

      unsafe-url:不管什么情况,总是发送Referer标头。

      strict-originReferer标头只包含域名,HTTPS 页面请求 HTTP 资源时不发送Referer标头。

      strict-origin-when-cross-origin:同源请求时Referer标头包含完整路径,跨域请求时只包含域名,HTTPS 页面请求 HTTP 资源时不发送该标头。

    • integrity: 包括请求的 subresource integrity 值(例如: sha256-BpfBw7ivV8q2jLiT13fxDYAe2tJllusRSZ273h2nFSE=)。
      integrity:指定一个哈希值,用于检查 HTTP 回应传回的数据是否等于这个预先设定的哈希值。

      比如,下载文件时,检查文件的 SHA-256 哈希值是否相符,确保没有被篡改

      fetch('http://site.com/file', {
        integrity: 'sha256-abcdef',
      });
      
    • signal:指定一个 AbortSignal 实例,用于取消fetch()请求

返回一个promiseresolve 时回传 Response 对象。

取消请求

let controller = new AbortController();

fetch(url, {
  signal: controller.signal,
});

controller.signal.addEventListener('abort', () => console.log('abort!'));
// controller.abort()方法用于发出取消信号。这时会触发abort事件,这个事件可以监听
controller.abort(); // 取消
// 可以通过controller.signal.aborted属性判断取消信号是否已经发出
console.log(controller.signal.aborted); //

当调用了abort方法后,controller实例就不能再使用了,controller.signal.aborted已经变成true了,该属性只读,不能修改值来实现再次使用(会报错),只能通过在创建一个AbortController实例来中断。

你可能感兴趣的:(javascript,javascript,ajax,前端)