How do I copy a Request object with a different URL?

房东的猫 提交于 2019-12-10 02:21:32

问题


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.


回答1:


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

https://fetch.spec.whatwg.org/#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.)



来源:https://stackoverflow.com/questions/34640286/how-do-i-copy-a-request-object-with-a-different-url

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!