最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - How do I copy a Request object with a different URL? - Stack Overflow

programmeradmin6浏览0评论

I'm writing a wrapper around fetch that I would like to add something to the URL before making the request e.g. identifying query parameters. I can't figure out how to make a copy of a given a Request object with a different URL than the original. My code looks like:

// My function which tries to modify the URL of the request
function addLangParameter(request) {
    const newUrl = request.url + "?lang=" + lang;
    return new Request(newUrl, /* not sure what to put here */);
}

// My fetch wrapper
function myFetch(input, init) {
    // Normalize the input into a Request object
    return Promise.resolve(new Request(input, init))
        // Call my modifier function
        .then(addLangParameter)
        // Make the actual request
        .then(request => fetch(request));
}

I tried putting the original request as the second arguent to the Request constructor, like so:

function addLangParameter(request) {
    const newUrl = request.url + "?lang=" + lang;
    return new Request(newUrl, request);
}

which seems to copy most of the attributes of the old request but doesn't seem to preserve the body of the old request. For example,

const request1 = new Request("/", { method: "POST", body: "test" });
const request2 = new Request("/new", request1);
request2.text().then(body => console.log(body));

I would expect to log "test", but instead it logs the empty string, because the body is not copied over.

Do I need to do something more explicit to copy all of the attributes correctly, or is there a nice shortcut that will do something reasonable for me?

I'm using the github/fetch polyfill, but have tested with both the polyfill and the native fetch implementation in the lastest Chrome.

I'm writing a wrapper around fetch that I would like to add something to the URL before making the request e.g. identifying query parameters. I can't figure out how to make a copy of a given a Request object with a different URL than the original. My code looks like:

// My function which tries to modify the URL of the request
function addLangParameter(request) {
    const newUrl = request.url + "?lang=" + lang;
    return new Request(newUrl, /* not sure what to put here */);
}

// My fetch wrapper
function myFetch(input, init) {
    // Normalize the input into a Request object
    return Promise.resolve(new Request(input, init))
        // Call my modifier function
        .then(addLangParameter)
        // Make the actual request
        .then(request => fetch(request));
}

I tried putting the original request as the second arguent to the Request constructor, like so:

function addLangParameter(request) {
    const newUrl = request.url + "?lang=" + lang;
    return new Request(newUrl, request);
}

which seems to copy most of the attributes of the old request but doesn't seem to preserve the body of the old request. For example,

const request1 = new Request("/", { method: "POST", body: "test" });
const request2 = new Request("/new", request1);
request2.text().then(body => console.log(body));

I would expect to log "test", but instead it logs the empty string, because the body is not copied over.

Do I need to do something more explicit to copy all of the attributes correctly, or is there a nice shortcut that will do something reasonable for me?

I'm using the github/fetch polyfill, but have tested with both the polyfill and the native fetch implementation in the lastest Chrome.

Share Improve this question edited Jan 6, 2016 at 19:30 Xymostech asked Jan 6, 2016 at 18:35 XymostechXymostech 9,8503 gold badges36 silver badges45 bronze badges 3
  • Don't show pseudo code: show real code. – Mike 'Pomax' Kamermans Commented Jan 6, 2016 at 18:38
  • @Mike'Pomax'Kamermans I added the actual code. I think it makes it harder to understand the actual problem, maybe it'll be helpful. – Xymostech Commented Jan 6, 2016 at 18:57
  • rather than harder, your new code actually makes it obvious what you're asking about, by showing your use of the Request object in the code itself. – Mike 'Pomax' Kamermans Commented Jan 6, 2016 at 19:07
Add a ment  | 

1 Answer 1

Reset to default 17

It looks like your best bet is to read the body using the Body interface that Requests implement:

https://fetch.spec.whatwg/#body

This can only be done asynchronously since the underlying "consume body" operation always reads asynchronously and returns a promise. Something like this should work:

const request = new Request('/old', { method: 'GET' });
const bodyP = request.headers.get('Content-Type') ? request.blob() : Promise.resolve(undefined);
const newRequestP =
  bodyP.then((body) =>
    new Request('/new', {
      method: request.method,
      headers: request.headers,
      body: body,
      referrer: request.referrer,
      referrerPolicy: request.referrerPolicy,
      mode: request.mode,
      credentials: request.credentials,
      cache: request.cache,
      redirect: request.redirect,
      integrity: request.integrity,
    })
  );

After doing that, newRequestP will be a promise that resolves to the request you want. Luckily, fetch is asynchronous anyway so your wrapper shouldn't be significantly hampered by this.

(Note: Reading the body using .blob() off of a request that does not have a body seems to return a zero-length Blob object, but it's incorrect to specify any body, even a zero-length one, on a GET or HEAD request. I believe that checking if the original request had Content-Type set is an accurate proxy for whether it has a body, which is what we really need to determine.)

发布评论

评论列表(0)

  1. 暂无评论