javascript Chrome - Fetch API 无法加载文件。如何解决?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/49971575/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-29 08:50:52  来源:igfitidea点击:

Chrome - Fetch API cannot load file. How to workaround?

javascriptgoogle-chromefirefoxfetch-apifile-uri

提问by davidesp

I have the following two files:

我有以下两个文件:

index.html

索引.html

<html>
<head>
<meta charset="utf-8" />
<title>Web Page</title>
<style type="text/css">
.text {
    display: inline-block;
    font-family: tahoma;
    font-size: 14px;
    max-width: 400px;
    background-color: #ddedff;
    padding: 10px;
    text-align: justify;
}
</style>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script type="text/javascript">
$(function(){
    get_data('info.txt');
});
function get_data(file) {
    var request = new Request(file);
    fetch(request).then(function(response) {
        return response.text().then(function(text) {
            $('.text').html(text);
        });
    });
}
</script>
</head>
<body>
    <div class="text"></div>
</body>
<html>

info.txt

信息.txt

Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.

When I open on Mozilla Firefoxthe file: README.htmlthrough this local URI:

当我打开Mozilla Firefox文件时:README.html通过这个本地URI

file:///C:/testing/README.html

it works as expected, I mean, the text on file: info.txtis displayed properly.

它按预期工作,我的意思是,文件中的文本:info.txt正确显示。

But when I open the same URIon Google ChromeI get a blank screen and the following error on the console:

但是当我打开它时,我在控制台URIGoogle Chrome看到一个空白屏幕和以下错误:

README.html:26 Fetch API cannot load file:///C:/testing/README.md. URL scheme must be "http" or "https" for CORS request.
get_data @ README.html:26
README.html:26 Uncaught (in promise) TypeError: Failed to fetch
    at get_data (README.html:26)
    at HTMLDocument.<anonymous> (README.html:21)
    at l (jquery.min.js:2)
    at c (jquery.min.js:2)

Do you have what can I do so I can open local files on Google Chromeas I can do on Mozilla Firefox?

你有什么我可以做的,所以我可以Google Chrome像我一样打开本地文件Mozilla Firefox

If I have to do some tweak on:

如果我必须做一些调整:

chrome://flags/

that's acceptable for me.

这对我来说是可以接受的。

EDIT

编辑

I tried launching Google Chromefrom the command line with the flag: --allow-file-access-from-filesas recommended herebut now I get the following error:

我尝试Google Chrome从带有标志的命令行启动:--allow-file-access-from-files按照此处的建议但现在出现以下错误:

README.html:26 Fetch API cannot load file:///C:/testing/README.md. URL scheme "file" is not supported.
get_data @ README.html:26
README.html:26 Uncaught (in promise) TypeError: Failed to fetch
    at get_data (README.html:26)
    at HTMLDocument.<anonymous> (README.html:21)
    at l (jquery.min.js:2)
    at c (jquery.min.js:2)

Thanks!

谢谢!

回答by Hashbrown

For chrome you still need --allow-file-access-from-files(and I recommend installing a separate chromeand using it solely for these projects to stay secure), but just shim fetch()for XMLHttpRequestfor file://requests:

对于铬,你仍然需要--allow-file-access-from-files(我建议安装一个单独的铬和仅使用它的这些项目保持安全性),但只是垫片fetch()用于XMLHttpRequestfile://请求:

if (/^file:\/\/\//.test(location.href)) {
    let path = './';
    let orig = fetch;
    window.fetch = (resource) => ((/^[^/:]*:/.test(resource)) ?
        orig(resource) :
        new Promise(function(resolve, reject) {
            let request = new XMLHttpRequest();

            let fail = (error) => {reject(error)};
            ['error', 'abort'].forEach((event) => { request.addEventListener(event, fail); });

            let pull = (expected) => (new Promise((resolve, reject) => {
                if (
                    request.responseType == expected ||
                    (expected == 'text' && !request.responseType)
                )
                    resolve(request.response);
                else
                    reject(request.responseType);
            }));

            request.addEventListener('load', () => (resolve({
                arrayBuffer : () => (pull('arraybuffer')),
                blob        : () => (pull('blob')),
                text        : () => (pull('text')),
                json        : () => (pull('json'))
            })));
            request.open('GET', resource.replace(/^\//, path));
            request.send();
        })
    );
}

This shim will;

这个垫片会;

  • only activate for html files opened locally (outer ifstatement),
  • call the normal fetch()for any url that doesn't specify protocol (and thus non-file://requests), and
  • will replace absolute paths (/root/bob.html) with ones relative to the current path (since that would dangerously evaluate to C:\or equivalent)
  • 仅激活本地打开的 html 文件(外部if语句),
  • fetch()为任何未指定协议(因此非file://请求)的url调用法线,以及
  • 将用/root/bob.html相对于当前路径的路径替换绝对路径 ( ) (因为这会危险地评估为C:\或等效)

Set pathto something else if your index.htmlisn't actually at the root for the project.
If you need support for init, or anything other than text(), you'll need to add it.
Explicit file://requests wont be fulfilled, that's on purpose, but if you reallydo know what you're doing, you'll know how to make this work for you, and if you don't you shouldn't.

path如果您index.html实际上不是项目的根,请设置为其他内容。
如果您需要对init或其他任何东西的支持,则text()需要添加它。
明确的file://请求不会被满足,这是故意的,但如果你真的知道你在做什么,你就会知道如何让这对你有用,如果你不知道,你就不应该。



The following is useful if you're going to be doing this for multiple files. Swap out './'for document.currentScript.getAttribute('data-root'). Now you can put that snippet into its own file, say filesystemHelper.js, and call like so in the various files:

如果您要为多个文件执行此操作,以下内容很有用。'./'换出document.currentScript.getAttribute('data-root'). 现在,您可以将该片段放入其自己的文件中,例如filesystemHelper.js,并在各种文件中像这样调用:

<script src="../filesystemHelper.js" data-root="../"></script>

Pretty snazzy.

相当时髦。