HTTP-запрос из JavaScript с использованием необработанных сообщений, включая заголовки

Я знаю, как сделать HTTP-запрос к моему REST API из javascript, используя jQuery или XMLHttpRequest. Сейчас я хочу сделать запрос без установки свойств для значений заголовка. Сообщение HTTP-запроса состоит из:

  • Строка запроса, такая как GET /images/logo.png HTTP/1.1, которая запрашивает ресурс с именем /images/logo.png с сервера
  • Заголовки, такие как Accept-Language: en
  • Пустая строка
  • Необязательное тело сообщения

Запрос к моему API должен выглядеть примерно так:

GET /myapi/myresource/1234 HTTP/1.1
Host: localhost:51127
Content-Type: application/x-www-form-urlencoded
Accept: application/json, text/csv
Authorization: Basic <base64 encoded credentials>

Я хотел бы открыть соединение с localhost:51127, отправить вышеприведенный текст и получить ответ. Это возможно в JavaScript?

Обновление: я знаю, как установить заголовки. Я просто хочу сделать это по-другому. Существует множество способов "создать" запрос, включая заголовки, и отправить его. Я просто хочу построить его вручную.

3 ответа

Решение

В Javascript нет поддержки сокетов. Вы можете создавать только HTTP-запросы, используя XMLHTTPRequest обертка или, возможно, обертки для этого, такие как jQuery.ajax, Это по разным причинам, главным образом, для безопасности.

Вы можете получить экземпляр объекта HmlHttpRequest и использовать setRequestHeader.

В jQuery есть обработчик beforeSend, который вы можете установить для получения реального объекта hxr.

  $.ajax({
      beforeSend: function(xhr){
          xhr.setRequestHeader("name","value");
       }
  ...
  })

Чтобы развить ответ lonesomeday, вот как это сделать на самом деле.

function rawRequest(txt,cb) {
  let x = new XMLHttpRequest(),
      lines = txt.split("\n"),
      methods = [
        "GET",
        "POST",
        "PATCH",
        "PUT",
        "DELETE",
        "HEAD",
        "OPTIONS"
      ],
      host, path, method, version, body = "", headers = {}
  lines.forEach((x, i) => {
    if(!x.includes(":")) {
      let ind;
      methods.forEach(m => {
        let tmpIndex = x.indexOf(m);
        
        if(tmpIndex > -1) {
          if(!method) {
            ind = tmpIndex;
            let words = x.split(" ");
            method = x.substring(
              tmpIndex,
              tmpIndex + 
              m.length
            );
            method = method && method.trim();
            path = words.find((y, k) => 
              y[0] === "/"
            )
            path = path && path.trim();
            version = (
              x
              .replace(method, "")
              .replace(path, "")
            ).trim();
          }
          
        }
      });
    } else {
      let indexOfSemiColon = x.indexOf(":");
      if(
        indexOfSemiColon > 0 &&
        indexOfSemiColon < x.length - 1
      ) {
      
        let key = x.substring(
          0,
          indexOfSemiColon
        ).trim(),
            value = x.substring(
              indexOfSemiColon + 1
            ).trim();
         headers[key] = value;
         if(key.toLowerCase() == "host") {
          host = value
         }
     }
    }
  });
  let inds = []
  txt.split(/\r?\n/).forEach((x,i)=>
    x === "" 
    && inds.push(i)
  )
  let afterTwoLineBreaksIndex;
  inds.forEach((x,i) => {
    if(
      i < inds.length - 2 &&
      inds[i] === "" &&
      inds[i + 1] === ""
    ) {
      afterTwoLineBreaksIndex = i + 1;
    }
  });
  if(afterTwoLineBreaksIndex) {
    body = txt.substring(
      afterTwoLineBreaksIndex
    )
  }
  x.onreadystatechange = () => {
    if(x.readyState == 4 && x.status == 200) {
      if(cb) cb(x.response);
    } 
  }
  if(host && path && method) {
    x.open(
      method, 
      "http://" //don't know how to differentiate between http & https, if some1 could help out would be greate
      + host 
      + path
    );
    
    for(let k in headers) {
      x.setRequestHeader(k, headers[k]);
    }
    
    x.send(body);
  }
  return {
    headers,
    body,
    method,
    host,
    path,
    version
  } //for testing just return all the values we found
}

console.log(
  rawRequest(`
    GET /search?q=test HTTP/2
    Host: www.bing.com
    User-Agent: curl/7.54.0
    Accept: */*`
  ),
  rawRequest(`
    GET /foo/bar HTTP/1.1
    Host: example.org
    User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.6; fr; rv:1.9.2.8) Gecko/20100722 Firefox/3.6.8
    Accept: */*
    Accept-Language: fr,fr-fr;q=0.8,en-us;q=0.5,en;q=0.3
    Accept-Encoding: gzip,deflate
    Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
    Keep-Alive: 115
    Connection: keep-alive
    Content-Type: application/x-www-form-urlencoded
    X-Requested-With: XMLHttpRequest
    Referer: http://example.org/test
    Cookie: foo=bar; lorem=ipsum;
  `),
   rawRequest(`
      GET /myapi/myresource/1234 HTTP/1.1
      Host: localhost:51127
      Content-Type: application/x-www-form-urlencoded
      Accept: application/json, text/csv
      Authorization: Basic <base64 encoded credentials>
   `)
  
 )

Пришел сюда в поисках того же. Я думаю, что было бы возможно построить что-то, что берет необработанный текст запроса и анализирует его в объект xmlHttpRequest, помещая заголовки и т. Д. В правильные свойства. Просьба прокомментировать ссылку, если что-то подобное уже существует. В принципе, если jQuery имеет функцию BuildRequestFromRaw(текст), это было бы замечательно.

Другие вопросы по тегам