FAQs: Web Server - racket/racket GitHub Wiki
See also: Web Development
See https://lexi-lambda.github.io/blog/2015/08/22/deploying-racket-applications-on-heroku/
-
You can pass base64 encoded values to the browser as cookie-values as long as you strip out both the embedded and trailing carriage-return-line-feed sequences.
The following code is incorrect because there are carriage-return-line-feed sequences.
(define (start request) (response/xexpr `(html (head (meta ((name "viewport") (content "initial-scale=1.0, user-scalable=no"))) (meta ((http-equiv "content-type") (content "text/html; charset=UTF-8")))) (body (div "Cookies!"))) #:headers (list (make-header #"Set-Cookie" #"Racketboy=XetM5o+My2BQYizra/y+NC7UJ0MxMjM0\r\nNTY2OQ==\r\n; Secure;"))))
To fix the problem, adjust the cookie value to
#"Racketboy=XetM5o+My2BQYizra/y+NC7UJ0MxMjM0NTY2OQ==; Secure;"
-
The Secure flag in the cookie only instructs the browser not to send the cookie over a non-secure connection. The server will happily pass a Secure-flag cookie over a non-secure connection.
To prevent the a Secure-flag cookie from being sent over a non secure connection, set the #:ssl
keyword argument to #t
in serve/servlet
.
Note: the correct MIME-type is important to get the browser to understand what you're sending over in the body of the response.
Client-side convention with respect to setting up client AJAX continuation seems to be to at least check the message-field equal to "OK", so be aware of this.
In addition to this code, You still need to send the response back to the client via one of Jay McCarthy's primitives such as send/suspend/dispatch
(if stateless), or send/back
(if stateful).
#|
USAGE:
(define res (make-xml-response `(xml "victory!")))
(call-with-output-string (response-output res))
-> "<xml>victory!</xml>"
|#
#lang racket
(require xml
web-server/servlet-env
web-server/http/response-structs
web-server/http/request-structs)
;; or just use #lang web-server and (require xml), if that's easier for you
(define (make-xml-response #:code [code 200]
#:message [message #"OK"]
#:seconds [seconds (current-seconds)]
#:mime-type [mime-type #"text/xml charset=utf-8"]
#:headers [headers (list (make-header #"Cache-Control" #"no-cache"))]
content)
(response/full code message seconds mime-type headers (list (string->bytes/utf-8 (xexpr->string content)))))
This doesn't do very much, but you can use as an AJAX test bed. I used this particular code to test whether setting browser cookies via AJAX works.
#lang web-server
(require web-server/servlet-env
web-server/http/xexpr
xml)
(define my-xml-response
(response/xexpr `(xml "victory!")
#:mime-type #"text/xml charset=utf-8"
#:headers (list (make-header #"Set-Cookie" #"name=mikey"))))
(define (start request)
(letrec ((response-generator (λ (make-url)
(response/xexpr `(html (head
(script ((type "text/javascript")) ,(format StartXMLHttpRequest (make-url receive-ajax-signal)))
(script ((type "text/javascript")) ,processChange))
(body (div ((onclick "alert('things are working');")) "Hello jay")
(div ((onclick "StartXMLHttpRequest('some data');")) "click for AJAX-type Request")
(a ((href ,(make-url receive-signal)))"click for browser-window-type Request"))))))
(receive-ajax-signal (λ (request)
my-xml-response))
(receive-signal (λ (request)
(send/suspend/dispatch response-generator))))
(send/suspend/dispatch response-generator)))
(define StartXMLHttpRequest (string-append "function StartXMLHttpRequest(post_data){ "
"obj = new XMLHttpRequest(); "
"obj.onreadystatechange = processChange;"
"obj.open('POST','~A',false); "
"obj.setRequestHeader('Content-Type','application/x-www-form-urlencoded'); "
"obj.send(post_data); "
"processChange();"
"} "))
(define processChange "function processChange(){alert('in processChange!');}")
(serve/servlet start
#:stateless? #t
#:launch-browser? #t
#:connection-close? #t
#:quit? #f
#:listen-ip #f
#:port 8000
#:servlet-path "/")