【问题标题】:HTML anchor tag's onclick not working with REST GET API callHTML 锚标记的 onclick 不适用于 REST GET API 调用
【发布时间】:2022-01-13 16:23:43
【问题描述】:

我正在尝试使用以下代码在单击href 时调用 REST GET API。我需要在 HTTP GET 请求中发送我的自定义标头。我希望 GET API 返回的 pdf 文件在单击 href 时在浏览器的新选项卡中打开,而原始页面保持在其选项卡中。

当我使用下面的代码时,它会在新选项卡中打开相同的页面 URL。当我查看在浏览器的 Javascript 控制台下进行的网络调用时,它确实表明 API 是使用所需的标头调用的。但浏览器本身不会显示。

<!DOCTYPE html>
<html>
<head>
<title> A jQuery click href </title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>

<script>
$(document).ready(function() {
    $('#click_href').click(function() {
        $.ajax({
        url: 'http://myserver:8080/path/download?a=A&b=B&filename=file.pdf',
        type: 'GET',
        dataType: 'pdf',
        beforeSend: function (xhr) {
            xhr.setRequestHeader('CLIENT_ID', 'WEB_APP');
        },
        success: function (response) {
            
        }
    })
    });
});
</script>

</head>
<body>
<h1> Demonstration for jQuery click href </h1>
<a href="#" id="click_href" target="_blank">Test by Curious Brain</a>
</body>
</html>

更新

这就是 Spring Boot REST 控制器返回 PDF 的方式。如果我在浏览器窗口中尝试直接下载 URL,则 PDF 会显示在浏览器中。

@CrossOrigin
    @RequestMapping(path = "/download", method = RequestMethod.GET, produces = MediaType.APPLICATION_PDF_VALUE)
    public ResponseEntity<InputStreamResource> download(
            @RequestParam("a") String a,
            @RequestParam("b") String b,
            @RequestParam("filename") String fileName) throws IOException {

        FileSystemResource pdfFile = new FileSystemResource(reportBaseDir + "/" + a + "/" + b + "/" + fileName);
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.parseMediaType(MediaType.APPLICATION_PDF_VALUE));
        headers.setAccessControlAllowMethods(Arrays.asList(HttpMethod.GET));
        headers.setAccessControlAllowHeaders(Arrays.asList("Content-Type"));
        headers.setContentDisposition(ContentDisposition.builder("inline").filename(fileName).build());
        headers.setCacheControl("no-cache, no-store, must-revalidate");
        headers.setPragma("no-cache");
        headers.setExpires(0L);
        headers.setContentLength(pdfFile.contentLength());

        return new ResponseEntity<InputStreamResource>(
                new InputStreamResource(pdfFile.getInputStream()), headers, HttpStatus.OK);
    }

根据下面给出的回复,我将我的 HTML 代码更新为:

<!DOCTYPE html>
<html>
<head>
<title> A jQuery click href </title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>

<script>
$(document).ready(function() {
    $('#click_href').click(function(e) {
        e.preventDefault();
        $.ajax({
        url: 'http://myserver:8080/path/download?a=A&b=B&filename=file.pdf',
        type: 'GET',
        dataType: 'pdf',
        beforeSend: function (xhr) {
            xhr.setRequestHeader('CLIENT_ID', 'WEB_APP');
        },
        success: function (response) {
            window.open("data:application/pdf," + escape(response), '_blank');
        }
    })
    });
});
</script>

</head>
<body>
<h1> Demonstration for jQuery click href </h1>
<a href="#" id="click_href">Test by Curious Brain</a>
</body>
</html>

即便如此,我仍然可以看到对下载 URL 进行了调用,但没有任何反应。我希望当单击 href 链接时,pdf 文件显示在浏览器的新选项卡中。

来自浏览器的 Javascript 控制台的网络跟踪:

Summary
URL: http://myserver:8080/path/download?a=A&b=B&filename=file.pdf
Status: 200
Source: Network
Address: <some ip>:8080
Initiator: 
jquery.min.js:2:82618


Request
GET /path/download HTTP/1.1
Accept: */*
Origin: null
Accept-Encoding: gzip, deflate
Host: myserver:8080
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.1 Safari/605.1.15
Accept-Language: en-US,en;q=0.9
Connection: keep-alive
CLIENT_ID: WEB_APP

Response
HTTP/1.1 200
Access-Control-Allow-Origin: *
Content-Type: application/pdf
Pragma: no-cache
Content-Disposition: inline; filename="file.pdf"
Keep-Alive: timeout=60
Access-Control-Allow-Methods: GET
Expires: Thu, 01 Jan 1970 00:00:00 GMT
Access-Control-Allow-Headers: Content-Type
Cache-Control: no-cache, no-store, must-revalidate
Date: Thu, 13 Jan 2022 21:19:02 GMT
Content-Length: 387717
Connection: keep-alive
Vary: Origin, Access-Control-Request-Method, Access-Control-Request-Headers

Query String Parameters
a: A
b: B
filename: file.pdf

更新 2:

这是我能做到的最接近的。但这只会下载文件。我尝试了window.open(…),但没有在浏览器中打开文件。


<!DOCTYPE html>
<html>
<head>
<title> A jQuery click href </title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>

<script>
$(document).ready(function() {
    $('#click_href').click(function(e) {
        e.preventDefault();
        $.ajax({
            //cache: false,
            type: 'GET',
            url: 'http:/myserver:8080/path/download?a=A&b=B&filename=file.pdf',
            //contentType: false,
            //processData: false,
            data: 'native',
            beforeSend: function (xhr) {
                xhr.setRequestHeader('CLIENT_ID', 'WEB_APP');
            },
            xhrFields: {
                responseType: 'blob'
            },
            success: function (response, status, xhr) {

                var filename = '';                   
                var disposition = xhr.getResponseHeader('Content-Disposition');
                alert(disposition);

                if (disposition) {
                    filename = disposition.split('"')[1];
                    alert(filename);
                }
                
                var linkelem = document.createElement('a');
                
                var blob = new Blob([response], { type: 'application/octet-stream' });                        
            
                var downloadUrl = window.URL.createObjectURL(blob);
                
                var a = document.createElement("a");
                a.href = downloadUrl;
                a.download = filename;
                document.body.appendChild(a);
                a.target = "_blank";
                //window.open(a);
                a.click();
            }
        });
    });
});
</script>

</head>
<body>
<h1> Demonstration for jQuery click href </h1>
<a href="#" id="click_href">Test by Curious Brain</a>
</body>
</html>

【问题讨论】:

  • 如果我用一些随机的 pdf 填充运行最后一段代码(应该打开 PDF 的代码),它会在浏览器中正确打开。因此,您的 PDF 或您为它们提供服务的方式必须有一些时髦的东西。我无法重现该问题,这表明问题可能与您目前显示的代码无关。你能创建一个runnable minimal reproducible example吗?
  • 我让它工作了。问题在于 JavaScript 代码中的 application/octet-stream。 mime 类型强制下载文件。当我将其更改为application/pdf 时,文件在浏览器中打开而不是下载。我将很快发布完整的解决方案和调查结果。一个奇怪的事情仍然是一个谜(对我的要求并不重要)是浏览器地址栏显示blob:null/6af2f4a4-ca4d-42fa-9962-c54ae3cd357c,我不知道如何让它显示文件名。

标签: javascript html jquery


【解决方案1】:

这是我如何让它工作的。注意代码cmets

重复一遍,要求是从 REST GET API 获取 PDF 文件并显示在浏览器中,但还要在请求中添加一些自定义 HTTP 标头 (CLIENT_ID, WEB_APP)

Spring Boot 休息控制器

@CrossOrigin
@RequestMapping(path = "/download", method = RequestMethod.GET, produces = MediaType.APPLICATION_PDF_VALUE)
public ResponseEntity<InputStreamResource> download(
    @RequestParam("a") String a,
    @RequestParam("b") String b,
    @RequestParam("filename") String fileName) throws IOException {
        FileSystemResource pdfFile = new FileSystemResource(a + "/" + b + "/" + fileName);
        HttpHeaders headers = new HttpHeaders();

        headers.setContentType(MediaType.parseMediaType(MediaType.APPLICATION_PDF_VALUE));
        //Since you already have the controller annotated with @CrossOrigin, you don't need the below line. Keeping this makes browsers complain that Access-Control-Allow-Origin has two '*', '*' values
        //headers.setAccessControlAllowOrigin("*");
        headers.setAccessControlAllowMethods(Arrays.asList(HttpMethod.GET));
        headers.setAccessControlAllowHeaders(Arrays.asList("Content-Type"));
        //has to be 'inline' if you want to display the PDF file in the browserheaders.setContentDisposition(ContentDisposition.builder("inline").filename(fileName).build());
        headers.setCacheControl("no-cache, no-store, must-revalidate");
        headers.setPragma("no-cache");
        headers.setExpires(0L);
        headers.setContentLength(pdfFile.contentLength());
        //Add the headers that you want to get via xhr.getResponseHeader() in JavaScript; without this, the value returned would be null  headers.setAccessControlExposeHeaders(Arrays.asList("Content-Disposition"));

        return new ResponseEntity<>(
                new InputStreamResource(pdfFile.getInputStream()), headers, HttpStatus.OK);
}

HTML

<!DOCTYPE html>
<html>
<head>
<title> A jQuery click href </title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>

<script>
$(document).ready(function() {
    $('#click_href').click(function(e) {
        e.preventDefault();
        $.ajax({
            //cache: false,
            type: 'GET',
            url: 'http://myserver:8080/path/download?a=A&b=B&filename=file.pdf',
            //contentType: false,
            //processData: false,
            //data: 'native',
            beforeSend: function (xhr) {
                xhr.setRequestHeader('CLIENT_ID', 'WEB_APP');
            },
            xhrFields: {
                responseType: 'blob' // important to be set to make this work
            },
            success: function (response, status, xhr) {

                var filename = '';                   
                var disposition = xhr.getResponseHeader('Content-Disposition');

                if (disposition) {
                    filename = disposition.split('"')[1];
                }
                // if this is application/octet-stream, the file will be forced to be downloaded instead of opening in the browser; make sure this is application/pdf
                var blob = new Blob([response], { type: 'application/pdf' });
            
                var downloadUrl = window.URL.createObjectURL(blob);
                
                var a = document.createElement('a');
                a.href = downloadUrl;
                //a.download = filename;
                //document.body.appendChild(a);
                a.target = "_blank";
                //window.open(a);
                a.click();
            }
        });
    });
});
</script>

</head>
<body>
<h1> Demonstration for jQuery click href </h1>
<a href="#" id="click_href">Test by Curious Brain</a>
</body>
</html>

网络跟踪

Summary
URL: http://myserver:8080/path/download?a=A&b=B&filename=file.pdf
Status: 200
Source: Network
Address: <ip redacted>:8080
Initiator: 
jquery.min.js:2:82618


Request
GET /path/download HTTP/1.1
Accept: */*
Origin: null
Accept-Encoding: gzip, deflate
Host: myserver:8080
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.2 Safari/605.1.15
Accept-Language: en-US,en;q=0.9
Connection: keep-alive
CLIENT_ID: WEB_APP

Response
HTTP/1.1 200
Access-Control-Allow-Origin: *
Content-Type: application/pdf
Pragma: no-cache
Content-Disposition: inline; filename="file.pdf"
Keep-Alive: timeout=60
Access-Control-Allow-Methods: GET
Expires: Thu, 01 Jan 1970 00:00:00 GMT
Access-Control-Expose-Headers: Content-Disposition
Access-Control-Allow-Headers: Content-Type
Cache-Control: no-cache, no-store, must-revalidate
Date: Fri, 14 Jan 2022 16:58:44 GMT
Content-Length: 397295
Connection: keep-alive
Vary: Origin, Access-Control-Request-Method, Access-Control-Request-Headers

Query String Parameters
a: A
b: B
filename: file.pdf

【讨论】:

    【解决方案2】:

    浏览器正在新窗口中打开当前页面,因为这是链接的作用。

    href="#" 表示“当前页面的顶部”,target="_blank" 表示“在新窗口或标签中”。

    JavaScript 没有在事件对象上调用 preventDefault,因此不会阻止这种行为。


    Ajax 请求是一个完全独立的 HTTP 请求,您在单击链接时运行它。

    它发出 HTTP 请求。

    数据返回给JS。

    success 函数已运行。

    数据被传递到response变量中。

    然后你……什么也不做。

    如果您想对来自 Ajax 请求的数据做某事,那么您必须实际做 某事

    也许类似于the answers to this question

    【讨论】:

    • 我尝试了您的建议以及您提供的链接中的一些内容。但每次,PDF 既不会显示在浏览器中,也不会下载。我的要求是在浏览器的新选项卡中显示 PDF。
    【解决方案3】:

    不确定您的 API 调用会返回什么响应,如果它返回 pdf 文件路径,那么您可以简单地使用 window.open();

    <script>
    $(document).ready(function() {
        $('#click_href').click(function(e) {
            e.preventDefault(); // this is to stop your page from reloading
            $.ajax({
            url: 'http://myserver:8080/path/download?a=A&b=B&filename=file.pdf',
            type: 'GET',
            dataType: 'pdf',
            beforeSend: function (xhr) {
                xhr.setRequestHeader('CLIENT_ID', 'WEB_APP');
            },
            success: function (response) {
                // If your response if url then you can use
                window.open(response, '_blank');
    
               // IF your response is base64 PDF data then you can use something like 
              window.open("data:application/pdf," + escape(response), '_blank'); 
    
            }
        })
        });
    });
    </script>
    

    您还需要从原始 a 标签中删除 target="_blank"

    【讨论】:

    • 嗨 Swapnil,我尝试了您的建议并更新了我的问题。但每次,PDF 既不会显示在浏览器中,也不会下载。我的要求是在浏览器的新选项卡中显示 PDF。
    猜你喜欢
    • 1970-01-01
    • 2015-07-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-07-08
    • 2013-07-14
    • 2019-03-24
    • 2010-11-25
    相关资源
    最近更新 更多