Racket servlet 提供静态文件
Racket servlet serve static files
我想尝试在 Racket 中编写一些博客或个人网站或本地网络服务。我已经完成教程 here and then I found this mailing list entry. In addition to that, I used the information from the documenation。基于 URL 的分派似乎比教程更容易,所以我继续这样做并获得了以下代码:
#lang racket
(provide/contract
(start (-> request? response?)))
(require
web-server/templates
web-server/servlet-env
web-server/servlet
web-server/dispatch)
;; =====
;; STATE
;; =====
(define (get-vocabulary-for-topic topic)
;; for now always returns the same
(list
(list "sich fuer eine Person entscheiden" "xuǎnzé" "32" "选择")
(list "teilnehmen" "cānyù" "14" "参与")
(list "die Wahl" "dàxuǎn" "43" "大选")))
;; ======================
;; APPS HANDLING REQUESTS
;; ======================
(define (vocabulary-app request topic)
(response/full
200 #"OK"
(current-seconds) TEXT/HTML-MIME-TYPE
empty
(list (string->bytes/utf-8 (render-vocabulary-page topic)))))
(define (vocabulary-overview-app request)
(response/xexpr
`(html
(head (title "Vocabulary Overview")
(link ((rel "stylesheet") (href "css/general.css") (type "text/css"))))
(body (p "This is an overview of vocabulary pages.")))))
(define (overview-app request)
(response/full
200 #"OK"
(current-seconds) TEXT/HTML-MIME-TYPE
empty
(list (string->bytes/utf-8 (render-overview-page)))))
;; ===============
;; RENDERING STUFF
;; ===============
(define (render-vocabulary-page topic)
(let
([vocabulary (get-vocabulary-for-topic topic)])
(let
([content (render-vocabulary-table vocabulary)]
[page-title "Vocabulary"]
[special-css-imports
(render-css-include "css/vocabulary-table.css")]
[special-js-imports ""]
[header ""]
[footer ""]
[navigation ""])
(include-template
"templates/base.html"))))
(define (render-vocabulary-table vocabulary)
(let
([table-headers (list "German" "Pinyin" "Tones" "Chinese")]
[word-list vocabulary])
(include-template "templates/vocabulary-table.html")))
(define (render-overview-page)
(let
([content
(let
([subpage-titles (list "vocabulary")])
(include-template "templates/overview.html"))]
[page-title "Overview"]
[special-css-imports ""]
[special-js-imports ""]
[header ""]
[footer ""]
[navigation ""])
(include-template
"templates/base.html")))
(define (render-css-include path)
(let
([path path])
(include-template "templates/css-link.html")))
;; ====================
;; ROUTES MANAGING CODE
;; ====================
(define (start request)
;; for now only calling the dispatch
;; we could put some action here, which shall happen before dispatch
(blog-dispatch request))
(define-values (blog-dispatch blug-url)
(dispatch-rules
[("index") overview-app]
[("vocabulary") vocabulary-overview-app]
[("vocabulary" (string-arg)) vocabulary-app]))
(define (respond-unknown-file req)
(let
([content (include-template "templates/unknown-file.html")]
[page-title "unknown file"]
[special-css-imports ""]
[special-js-imports ""]
[header ""]
[footer ""]
[navigation ""])
(response/full
404 #"ERROR"
(current-seconds) TEXT/HTML-MIME-TYPE
empty
(list
(string->bytes/utf-8
(include-template "templates/base.html"))))))
;; ===========================
;; ADDED FOR RUNNING A SERVLET
;; ===========================
(serve/servlet
start
#:servlet-path "/index" ; default URL
#:extra-files-paths (list (build-path (current-directory) "static")) ; directory for static files
#:port 8000 ; the port on which the servlet is running
#:servlet-regexp #rx""
#:launch-browser? true ; should racket show the servlet running in a browser upon startup?
;; #:quit? false ; ???
#:listen-ip false ; the server will listen on ALL available IP addresses, not only on one specified
#:server-root-path (current-directory)
#:file-not-found-responder respond-unknown-file)
到目前为止这工作正常,除了我的静态目录中的任何文件,实际上在 static
目录的子目录中,即 css
找不到,当我导航到任何 "subpages".
我的意思是,"main page" 类似于 localhost:8000/index
或 localhost:8000/vocabulary
,子页面类似于 localhost:8000/vocabulary/something
。
模板渲染好像搞错了,并不总是从应用目录的根目录访问static目录,而是只看localhost:8000/vocabulary/css/general.css
,而应该看localhost:8000/css/general.css
,当我去任何 "main page".
这是主页上的截图:
它在子页面上:
所以静态目录似乎会根据 URL 访问的内容而改变。起初我以为我终于明白了如何提供静态文件,但似乎我还没有,我不知道如何以最好的方式解决这个问题。
这是我的目录结构:
/home/xiaolong/development/Racket/blog2
- static/
- css/
general.css
vocabulary-table.css
+ img/
+ js/
- templates/
base.html
css-link.html
js-link.html
overview.html
unknown-file.html
vocabulary-table.html
blog-demo.rkt
blog.rkt
如何修复静态文件的路径?
我希望能够在代码中简单地键入 css/something.css
,无论是哪个应用程序或路由,它都应该提供文件,我不想根据我的路由更改包含路径我正在处理代码。
我用于 运行 服务器的命令很简单:
racket blog.rkt
从项目的根目录。
在我看来这确实是一个 HTML 问题,而不是球拍问题。具体来说,看起来您需要将这些指定为绝对路径,而不是相对路径。因此,在您的代码中,您可能想要更改
(define (vocabulary-overview-app request)
(response/xexpr
`(html
(head (title "Vocabulary Overview")
(link ((rel "stylesheet") (href "css/general.css") (type "text/css"))))
(body (p "This is an overview of vocabulary pages.")))))
至
(define (vocabulary-overview-app request)
(response/xexpr
`(html
(head (title "Vocabulary Overview")
(link ((rel "stylesheet") (href "/css/general.css") (type "text/css"))))
(body (p "This is an overview of vocabulary pages.")))))
(注意 css 文件路径中的前导斜杠)
这是否回答了您的问题?
这里的问题是不理解绝对路径与相对路径的概念、基本 URL 的概念,以及它们如何共同构成给定资源的完全限定 URL .
RFC 3986 是如何构建和处理 URL 的参考。请注意,它实际上使用术语统一资源标识符 URI 而不是 URL。它取代了以前使用旧的和弃用的 URL 术语的文档。
但为了与原始问题保持一致,我将继续使用 URL 术语。
理解 RFC 3986 第 4.1 节中相对引用的概念很重要,它可以写成相对路径或绝对路径。
在这里,解释 URLs 的代理是您的浏览器,它只是处理 URLs 您的服务器使用 RFC 3986 作为其如何 URLs 应该可以工作。
完全限定的 URL 包括协议和主机域以及端口号(如果需要),以及给出文档或资源相对于协议和主机域的位置的路径。
因此,在您的情况下,CSS 文件的正确完全限定 URL 应该是 http://localhost:8000/css/general.css
From RFC 3986 Section 3
http 和 localhost:8000 分别称为协议方案和权限组件,构成您网站的主要标识符,http://localhost:8000 该标识符之后的任何内容都称为路径组件,它位于查询或 URL 以“?”开头的片段组件之前。或“#”。
路径组件旨在模拟 UNIX 文件路径约定并构建树状层次结构,使您可以表达某些给定资源相对于您网站标识符的位置。您需要考虑一些规则。
相对参考分辨率在Section 5 of RFC 3986中给出。关键概念是基础 URL,它与相对引用一起使用以构造完全限定的 URL.
当您的浏览器访问位于 http://localhost:8000/vocabulary/something 的页面时,它会看到 css/general。 css这是写成相对路径的相对引用。按照解析算法,base URL 被取为原来用于访问页面 http://localhost:8000/vocabulary/something[= 的 URL 57=]
由于末尾没有尾部斜杠,最右侧斜杠右侧的路径子组件被删除,给你 http://localhost:8000/vocabulary/. URL 相对引用 css/general.css 然后附加在重写的基本 URL 路径的末尾,给你 http://localhost:8000/vocabulary/css/general.css,导致浏览器尝试检索不存在的资源时出现404错误。
如果相反,浏览器会看到 /css/general.css,这是写成绝对路径的相对引用。基础 URL 又是 http://localhost:8000/vocabulary/something。由于相对引用是绝对路径,因此您的网站标识符右侧的整个路径都将被删除
给你 http://localhost:8000。然后将相对引用附加到重写的基础 URL,给你 http://localhost:8000/css/general.css 这是正确完全合格 URL.
请注意,如果您碰巧访问了具有以下内容的页面 URL http://localhost:8000/vocabulary/something/尾部斜杠。然后任何相对路径引用如 css/general.css 将被合并以构造
完整的 URL http://localhost:8000/vocabulary/something/css/general.css 因为按照算法,浏览器会看到在原始基础 URL 的末尾有一个尾部斜杠,并且不会删除最后一个路径子组件(或者更确切地说,将空子组件删除到尾部斜杠的右侧)
我想尝试在 Racket 中编写一些博客或个人网站或本地网络服务。我已经完成教程 here and then I found this mailing list entry. In addition to that, I used the information from the documenation。基于 URL 的分派似乎比教程更容易,所以我继续这样做并获得了以下代码:
#lang racket
(provide/contract
(start (-> request? response?)))
(require
web-server/templates
web-server/servlet-env
web-server/servlet
web-server/dispatch)
;; =====
;; STATE
;; =====
(define (get-vocabulary-for-topic topic)
;; for now always returns the same
(list
(list "sich fuer eine Person entscheiden" "xuǎnzé" "32" "选择")
(list "teilnehmen" "cānyù" "14" "参与")
(list "die Wahl" "dàxuǎn" "43" "大选")))
;; ======================
;; APPS HANDLING REQUESTS
;; ======================
(define (vocabulary-app request topic)
(response/full
200 #"OK"
(current-seconds) TEXT/HTML-MIME-TYPE
empty
(list (string->bytes/utf-8 (render-vocabulary-page topic)))))
(define (vocabulary-overview-app request)
(response/xexpr
`(html
(head (title "Vocabulary Overview")
(link ((rel "stylesheet") (href "css/general.css") (type "text/css"))))
(body (p "This is an overview of vocabulary pages.")))))
(define (overview-app request)
(response/full
200 #"OK"
(current-seconds) TEXT/HTML-MIME-TYPE
empty
(list (string->bytes/utf-8 (render-overview-page)))))
;; ===============
;; RENDERING STUFF
;; ===============
(define (render-vocabulary-page topic)
(let
([vocabulary (get-vocabulary-for-topic topic)])
(let
([content (render-vocabulary-table vocabulary)]
[page-title "Vocabulary"]
[special-css-imports
(render-css-include "css/vocabulary-table.css")]
[special-js-imports ""]
[header ""]
[footer ""]
[navigation ""])
(include-template
"templates/base.html"))))
(define (render-vocabulary-table vocabulary)
(let
([table-headers (list "German" "Pinyin" "Tones" "Chinese")]
[word-list vocabulary])
(include-template "templates/vocabulary-table.html")))
(define (render-overview-page)
(let
([content
(let
([subpage-titles (list "vocabulary")])
(include-template "templates/overview.html"))]
[page-title "Overview"]
[special-css-imports ""]
[special-js-imports ""]
[header ""]
[footer ""]
[navigation ""])
(include-template
"templates/base.html")))
(define (render-css-include path)
(let
([path path])
(include-template "templates/css-link.html")))
;; ====================
;; ROUTES MANAGING CODE
;; ====================
(define (start request)
;; for now only calling the dispatch
;; we could put some action here, which shall happen before dispatch
(blog-dispatch request))
(define-values (blog-dispatch blug-url)
(dispatch-rules
[("index") overview-app]
[("vocabulary") vocabulary-overview-app]
[("vocabulary" (string-arg)) vocabulary-app]))
(define (respond-unknown-file req)
(let
([content (include-template "templates/unknown-file.html")]
[page-title "unknown file"]
[special-css-imports ""]
[special-js-imports ""]
[header ""]
[footer ""]
[navigation ""])
(response/full
404 #"ERROR"
(current-seconds) TEXT/HTML-MIME-TYPE
empty
(list
(string->bytes/utf-8
(include-template "templates/base.html"))))))
;; ===========================
;; ADDED FOR RUNNING A SERVLET
;; ===========================
(serve/servlet
start
#:servlet-path "/index" ; default URL
#:extra-files-paths (list (build-path (current-directory) "static")) ; directory for static files
#:port 8000 ; the port on which the servlet is running
#:servlet-regexp #rx""
#:launch-browser? true ; should racket show the servlet running in a browser upon startup?
;; #:quit? false ; ???
#:listen-ip false ; the server will listen on ALL available IP addresses, not only on one specified
#:server-root-path (current-directory)
#:file-not-found-responder respond-unknown-file)
到目前为止这工作正常,除了我的静态目录中的任何文件,实际上在 static
目录的子目录中,即 css
找不到,当我导航到任何 "subpages".
我的意思是,"main page" 类似于 localhost:8000/index
或 localhost:8000/vocabulary
,子页面类似于 localhost:8000/vocabulary/something
。
模板渲染好像搞错了,并不总是从应用目录的根目录访问static目录,而是只看localhost:8000/vocabulary/css/general.css
,而应该看localhost:8000/css/general.css
,当我去任何 "main page".
这是主页上的截图:
它在子页面上:
所以静态目录似乎会根据 URL 访问的内容而改变。起初我以为我终于明白了如何提供静态文件,但似乎我还没有,我不知道如何以最好的方式解决这个问题。
这是我的目录结构:
/home/xiaolong/development/Racket/blog2
- static/
- css/
general.css
vocabulary-table.css
+ img/
+ js/
- templates/
base.html
css-link.html
js-link.html
overview.html
unknown-file.html
vocabulary-table.html
blog-demo.rkt
blog.rkt
如何修复静态文件的路径?
我希望能够在代码中简单地键入 css/something.css
,无论是哪个应用程序或路由,它都应该提供文件,我不想根据我的路由更改包含路径我正在处理代码。
我用于 运行 服务器的命令很简单:
racket blog.rkt
从项目的根目录。
在我看来这确实是一个 HTML 问题,而不是球拍问题。具体来说,看起来您需要将这些指定为绝对路径,而不是相对路径。因此,在您的代码中,您可能想要更改
(define (vocabulary-overview-app request)
(response/xexpr
`(html
(head (title "Vocabulary Overview")
(link ((rel "stylesheet") (href "css/general.css") (type "text/css"))))
(body (p "This is an overview of vocabulary pages.")))))
至
(define (vocabulary-overview-app request)
(response/xexpr
`(html
(head (title "Vocabulary Overview")
(link ((rel "stylesheet") (href "/css/general.css") (type "text/css"))))
(body (p "This is an overview of vocabulary pages.")))))
(注意 css 文件路径中的前导斜杠)
这是否回答了您的问题?
这里的问题是不理解绝对路径与相对路径的概念、基本 URL 的概念,以及它们如何共同构成给定资源的完全限定 URL .
RFC 3986 是如何构建和处理 URL 的参考。请注意,它实际上使用术语统一资源标识符 URI 而不是 URL。它取代了以前使用旧的和弃用的 URL 术语的文档。
但为了与原始问题保持一致,我将继续使用 URL 术语。
理解 RFC 3986 第 4.1 节中相对引用的概念很重要,它可以写成相对路径或绝对路径。
在这里,解释 URLs 的代理是您的浏览器,它只是处理 URLs 您的服务器使用 RFC 3986 作为其如何 URLs 应该可以工作。
完全限定的 URL 包括协议和主机域以及端口号(如果需要),以及给出文档或资源相对于协议和主机域的位置的路径。
因此,在您的情况下,CSS 文件的正确完全限定 URL 应该是 http://localhost:8000/css/general.css
From RFC 3986 Section 3 http 和 localhost:8000 分别称为协议方案和权限组件,构成您网站的主要标识符,http://localhost:8000 该标识符之后的任何内容都称为路径组件,它位于查询或 URL 以“?”开头的片段组件之前。或“#”。
路径组件旨在模拟 UNIX 文件路径约定并构建树状层次结构,使您可以表达某些给定资源相对于您网站标识符的位置。您需要考虑一些规则。
相对参考分辨率在Section 5 of RFC 3986中给出。关键概念是基础 URL,它与相对引用一起使用以构造完全限定的 URL.
当您的浏览器访问位于 http://localhost:8000/vocabulary/something 的页面时,它会看到 css/general。 css这是写成相对路径的相对引用。按照解析算法,base URL 被取为原来用于访问页面 http://localhost:8000/vocabulary/something[= 的 URL 57=]
由于末尾没有尾部斜杠,最右侧斜杠右侧的路径子组件被删除,给你 http://localhost:8000/vocabulary/. URL 相对引用 css/general.css 然后附加在重写的基本 URL 路径的末尾,给你 http://localhost:8000/vocabulary/css/general.css,导致浏览器尝试检索不存在的资源时出现404错误。
如果相反,浏览器会看到 /css/general.css,这是写成绝对路径的相对引用。基础 URL 又是 http://localhost:8000/vocabulary/something。由于相对引用是绝对路径,因此您的网站标识符右侧的整个路径都将被删除 给你 http://localhost:8000。然后将相对引用附加到重写的基础 URL,给你 http://localhost:8000/css/general.css 这是正确完全合格 URL.
请注意,如果您碰巧访问了具有以下内容的页面 URL http://localhost:8000/vocabulary/something/尾部斜杠。然后任何相对路径引用如 css/general.css 将被合并以构造 完整的 URL http://localhost:8000/vocabulary/something/css/general.css 因为按照算法,浏览器会看到在原始基础 URL 的末尾有一个尾部斜杠,并且不会删除最后一个路径子组件(或者更确切地说,将空子组件删除到尾部斜杠的右侧)