NodeJS - https - TypeError [ERR_INVALID_HTTP_TOKEN]: имя заголовка должно быть действительным токеном HTTP ["Принять"] - PullRequest
6 голосов
/ 27 мая 2020

У меня есть код NodeJS, который использует модуль https как: https.request(options, (res) => {......, где options - это объект типа

const options = {
    hostname: SERVICE_HOSTNAME,
    path: BASE_PATH,
    method: 'GET',
    headers: {
        'Content-Type': 'application/json',
        'Accept​': 'application/json',
        ApplicationId,
        Authorization
    }
  };

Мои проблемы начинаются, когда я добавляю заголовок Accept. Я получаю сообщение об ошибке:

TypeError [ERR_INVALID_HTTP_TOKEN]: Header name must be a valid HTTP token ["Accept​"]
    at ClientRequest.setHeader (_http_outgoing.js:472:3)
    at new ClientRequest (_http_client.js:203:14)
    at Object.request (https.js:289:10)

Как заголовок Accept будет недействительным?

Ответы [ 3 ]

16 голосов
/ 29 мая 2020

Это безумие, но у вас есть лишний символ в строке «Принять». Если вы запустите

console.log('Accept​'.charCodeAt(6)) // prints 8203

(вы должны запустить его с вашей копией «Принять» из вашего вопроса, который, как я полагаю, скопирован из другого места)

Unicode 8203 равен пробел нулевой ширины , следовательно, он не виден нам, людям :)


Кстати, изначально я обнаружил символ, скопировав его в узел REPL и заметив «квадрат» в выводе консоли после получения ошибки.

Затем я попытался скопировать ваш код в свой редактор IntelliJ и был приятно удивлен, увидев это предупреждение:

enter image description here

7 голосов
/ 29 мая 2020

hlfrmn уже обнаружил эту хитрую ошибку и дал правильный ответ, на всякий случай, если кому-то еще интересно:

Начиная с версии 14.3.0 http модуль узла будет выполнять validateHeaderName и validateHeaderValue для каждой пары ключ-значение, указанной в заголовках параметров запроса.

Итак, если вы выполните

const {validateHeaderName} = require('http');

try {
    const options = {
        method: 'GET',
        headers: {
            'Content-Type': 'application/json',
            'Accept​': 'application/json',
        }
    };
    for (const header in options.headers) {
        validateHeaderName(header);
    }

} catch (err) {
    console.log(err);
}

, указанная ошибка будет напечатана:

TypeError [ERR_INVALID_HTTP_TOKEN]: Header name must be a valid HTTP token ["Accept​"] will be printed from the catch block.
1 голос
/ 29 мая 2020

Я не ел из-за вашего вопроса T_T

Как сказал @hlfrmn, у вас есть редкий символ в вашем слове Accept !!

Я воспроизвел ошибку:

const https = require('https');

//copied from origin question
var copiedOptions = {
  headers: {
    'Content-Type': 'application/json',
    "Accept​": 'application/json'
  }
}

var writedOptions = {
  headers: {
    'Content-Type': 'application/json',
    "Accept": 'application/json'
  }
}

https.get('https://api.nasa.gov/planetary/apod?api_key=DEMO_KEY',writedOptions, (resp) => {
  let data = '';

  // A chunk of data has been recieved.
  resp.on('data', (chunk) => {
    data += chunk;
  });

  // The whole response has been received. Print out the result.
  resp.on('end', () => {
    console.log(JSON.parse(data).explanation);
  });

}).on("error", (err) => {
  console.log("Error: " + err.message);
});

Если вы попробуете с copiedOptions , вы получите ту же ошибку.


Начиная с Node v10.20.1

Поиск в https://github.com/nodejs/node/tree/master и stackTrace: _http_outgoing. js: 472

at ClientRequest.setHeader (_http_outgoing.js:472:3)

Я основал это:

const tokenRegExp = /^[\^_`a-zA-Z\-0-9!#$%&'*+.|~]+$/;
/**
 * Verifies that the given val is a valid HTTP token
 * per the rules defined in RFC 7230
 * See https://tools.ietf.org/html/rfc7230#section-3.2.6
 */
function checkIsHttpToken(val) {
  return tokenRegExp.test(val);
}

Это регулярное выражение гарантирует, что имя заголовка разрешает только токены или символы в соответствии с https://tools.ietf.org/html/rfc7230#section -3.2.6

Возможно, более ранняя проверка в ядре nodejs может помочь:

В имени заголовка указан недопустимый символ!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...