I created a simple http2 server,
If I send a request to it with curl, it responds with some headers, although I did not set them explicity. How can I acces them inside the requesthandling function ( sayhello )? My code ( I've never used golang before)
server.go
package main
import (
"net/http"
"strings"
"fmt"
"github.com/gorilla/mux"
"golang.org/x/net/http2"
)
func sayHello(w http.ResponseWriter, r *http.Request) {
message := r.URL.Path
message = strings.TrimPrefix(message, "/")
message = "Hello " + message
w.Header().Set("myFirst", "golangQuestion")
w.Write([]byte(message))
for k, v := range w.Header() {
fmt.Println("[RESPONSE][Header]", k,":", v)
}
}
func main() {
router := mux.NewRouter()
router.PathPrefix("/").HandlerFunc(sayHello) // catch everything else rule
var srv = &http.Server{
Addr: "127.0.0.1:8081",
}
http2.ConfigureServer(srv, nil)
srv.Handler = router
sslCert := "./ssl.cert"
sslKey := "./ssl.key"
if err := srv.ListenAndServeTLS(sslCert, sslKey); err != nil {
panic(err)
}
}
Sending request:
curl --head --insecure https://127.0.0.1:8081
HTTP/1.1 200 OK
Myfirst: golangQuestion
Date: Tue, 18 Jun 2019 09:18:29 GMT
Content-Length: 6
Content-Type: text/plain; charset=utf-8
I can see that some headers are sent back, the one which I set explicitly is also recieved, but the output of
go run server.go
[RESPONSE][Header] Myfirst : [golangQuestion]
How can I acces the other headers, which were not explicitly set, but recieved by curl as well? I loopd through w.Headers, but it did not contain the implicitly set headers
for k, v := range w.Header() {
fmt.Println("[RESPONSE][Header]", k,":", v)
}
My expectation that the output of go run server.go shall be something like this:
[RESPONSE][Header] Myfirst : [golangQuestion]
[RESPONSE][Header] Date: [2019.02.12 ]
[RESPONSE][Header] Content-Length: [6]
Those headers are sent automatically when you call ResponseWriter.Write(). Quoting from its doc:
// Write writes the data to the connection as part of an HTTP reply.
//
// If WriteHeader has not yet been called, Write calls
// WriteHeader(http.StatusOK) before writing the data. If the Header
// does not contain a Content-Type line, Write adds a Content-Type set
// to the result of passing the initial 512 bytes of written data to
// DetectContentType. Additionally, if the total size of all written
// data is under a few KB and there are no Flush calls, the
// Content-Length header is added automatically.
//
// Depending on the HTTP protocol version and the client, calling
// Write or WriteHeader may prevent future reads on the
// Request.Body. For HTTP/1.x requests, handlers should read any
// needed request body data before writing the response. Once the
// headers have been flushed (due to either an explicit Flusher.Flush
// call or writing enough data to trigger a flush), the request body
// may be unavailable. For HTTP/2 requests, the Go HTTP server permits
// handlers to continue to read the request body while concurrently
// writing the response. However, such behavior may not be supported
// by all HTTP/2 clients. Handlers should read before writing if
// possible to maximize compatibility.
Write([]byte) (int, error)
ResponseWriter.Header() contains only the headers set explicitly. The Content-Type and Content-Length were sent by w.Write().
Note: if you want to suppress such automatic headers, you have to set their values to nil, e.g.:
w.Header()["Date"] = nil
Also note that if you set the values of such headers manually, those values will be sent without being changed.
I am in the process of scraping public data regarding metheorology for a project (data science), and in order to effectively do that I need to change the proxy used on my scrapy requests in the event of a 403 response code.
For this, I have defined a download middleware to handle such situation, which is as follows
class ProxyMiddleware(object):
def process_response(self, request, response, spider):
if response.status == 403:
f = open("Proxies.txt")
proxy = random_line(f) # Just returns a random line from the file with a valid structure ("http://IP:port")
new_request = Request(url=request.url)
new_request.meta['proxy'] = proxy
spider.logger.info("[Response 403] Changed proxy to %s" % proxy)
return new_request
return response
After properly adding the class to settings.py, I expected this middleware to deal with 403 responses by generating a new request with the new proxy, hence finishing in a 200 response. The observed behaviour is that it actually gets executed (I can see the Logger info about Changed proxy), but the new request does not seem to be made. Instead, I'm getting this:
2018-12-26 23:33:19 [bot_2] INFO: [Response] Changed proxy to https://154.65.93.126:53281
2018-12-26 23:33:26 [bot_2] INFO: [Response] Changed proxy to https://176.196.84.138:51336
... indefinitely with random proxies, which makes me think that I'm still retrieving 403 errors and the proxy is not changing.
Reading the documentation, regarding process_response, it states:
(...) If it returns a Request object, the middleware chain is halted and the returned request is rescheduled to be downloaded in the future. This is the same behavior as if a request is returned from process_request().
Is it possible that "in the future" is not "right after it is returned"? How should I do to change the proxy for all requests from that moment on?
Scrapy will drop duplicate requests to the same url by default, so that's probably what's happening on your spider. To check if this is your case you can set this settings:
DUPEFILTER_DEBUG=True
LOG_LEVEL='DEBUG'
To solve this you should add dont_filter=True:
new_request = Request(url=request.url, dont_filter=True)
Try this:
class ProxyMiddleware(object):
def process_response(self, request, response, spider):
if response.status == 403:
f = open("Proxies.txt")
proxy = random_line(f)
new_request = Request(url=request.url)
new_request.meta['proxy'] = proxy
spider.logger.info("[Response 403] Changed proxy to %s" % proxy)
return new_request
else:
return response
A better approach would be to use scrapy random proxies module instead:
'DOWNLOADER_MIDDLEWARES' : {
'rotating_proxies.middlewares.RotatingProxyMiddleware': 610,
'rotating_proxies.middlewares.BanDetectionMiddleware': 620
},
I tried sending a HTTP Get to a device's Restful API via Postman and it worked fine returning all text I was expecting. Postman suggested Ruby code for the request was the following:
url = URI('http://192.168.1.5/rest/op/BD1FD3D893613E79')
http = Net::HTTP.new(url.host, url.port)
request = Net::HTTP::Get.new(url)
request.basic_auth 'admin', 'admin'
request["accept"] = 'Application/json'
response = http.request(request)
puts response.read_body
but when I tried that in my code, it is returning a truncated response (missing lines) and I have to resend the same Get multiple times to get the entire text response response.
Is there anything missing in the Ruby code above that's causing this truncated response?
Update 1
I tried this
url = URI('http://192.168.1.5/rest/op/BD1FD3D893613E79')
http = Net::HTTP.new(url.host, url.port)
request = Net::HTTP::Get.new(url)
request.basic_auth 'admin', 'admin'
request["accept"] = 'Application/json'
response = http.request(request)
puts response.read_body
response.read_body do |segment|
puts segment.to_s
end
and that generated this error
IOError (Net::HTTPOK#read_body called twice):
Update 2
I tried this
1073 url = URI('http://192.168.1.5/rest/op/BD1FD3D893613E79')
1074 http = Net::HTTP.new(url.host, url.port)
1075 request = Net::HTTP::Get.new(url.to_s)
1076 request.basic_auth 'admin', 'admin'
1077 request["accept"] = 'Application/json'
1078 response = http.request(request)
1079 response.read_body do |segment|
1080 puts segment.to_s
1081 end
and got this error
IOError (Net::HTTPOK#read_body called twice):
app/controllers/Apps_controller.rb:1079:in `block in get_config'
app/controllers/Apps_controller.rb:1045:in `each'
app/controllers/Apps_controller.rb:1045:in `get_config'
Based on: http://ruby-doc.org/stdlib-1.9.3/libdoc/net/http/rdoc/Net/HTTPResponse.html#method-i-read_body
read_body returns the body as stream, so you should iterate it, something like:
response.read_body do |segment|
puts segment
end
If you want to get the full body just use: response.body
Looks very similar....
We are getting truncated responses when pulling a set of artifacts (zip files) from a Bamboo server and writing to local storage. It happens inconsistently, on only one of 8 servers, and not always the same file. Seems always to be the last portion of the file that is missing.
Using Ruby 2.0.0p598 and net/http.
The zip files range in size from 2 mb to 34 mb.
While we haven't figured out why the response body has been truncated, our workaround is to compare the expected content length (in the response header), to the response body size. If they don't match, try it again. Example code:
package = "packages/applicationname.zip"
def retrieve(package)
# generates the Bamboo url for the given package
sourceURL = package_url package
expectedLength = 0
bodyLength = 1
# Try to catch the bad download and re-issue the GET request,
while expectedLength != bodyLength do
# add a counter if worried about getting stuck
# issue the request to get the current package zip file
response = my_request_wrapper sourceURL
expectedLength = response['content-length'].to_i
theBody = response.body
bodyLength = theBody.size
if expectedLength != bodyLength then
puts "!! SIZE MISMATCH !!"
else
# the response body is good, process as needed
open package, 'wb' do |io|
io.write theBody
end
end
end
end
def my_request_wrapper(url)
uri = URI.parse(url)
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
req = Net::HTTP::Get.new(uri.request_uri)
req.basic_auth("user", "pwd")
return http.request req
end
I was using OSX Sierra, rvm, and ruby 2.3.0
Updating my rvm, ruby, and gems seems to have fixed the problem for me
I think you must call http.start before you call http.request.
Not sure why, but I see the same.
Intuit offers these instructions for uploading attachments (which become Attachable objects that can be associated with one or more transactions).
I believe I'm using python's requests module (via rauth's OAuth1Session module—see below for how I'm creating the session object) to generate these requests. Here's the code leading up to the request:
print request_type
print url
print headers
print request_body
r = session.request(request_type, url, header_auth,
self.company_id, headers = headers,
data = request_body, **req_kwargs)
result = r.json()
print json.dumps(result, indent=4)
and the output of these things:
POST
https://quickbooks.api.intuit.com/v3/company/0123456789/upload
{'Accept': 'application/json'}
Content-Disposition: form-data; name="Invoice 003"; filename="Invoice 003.pdf"
Content-Type: application/pdf
<#INCLUDE */MyDir/Invoice 003.pdf*#>
{
"Fault": {
"type": "SystemFault",
"Error": [
{
"Message": "An application error has occurred while processing your request",
"code": "10000",
"Detail": "System Failure Error: Cannot consume content type"
}
]
},
"time": "[timestamp]"
}
I have confirmed (by uploading an attachment through the QBO web UI and then querying the Attachable object through the API) that application/pdf is included in the list of acceptable file types.
At sigmavirus24's suggestion, I tried removing the Content-Type line from the headers, but I got the same result.
Here's how I'm creating the session object (which, again, is working fine for other QBO v3 API requests of every type you see in Intuit's API Explorer):
from rauth import OAuth1Session
def create_session(self):
if self.consumer_secret and self.consumer_key and self.access_token_secret and self.access_token:
session = OAuth1Session(self.consumer_key,
self.consumer_secret,
self.access_token,
self.access_token_secret,
)
self.session = session
else:
raise Exception("Need four creds for Quickbooks.create_session.")
return self.session
What might I be missing here?
EDIT: current area of exploration is here; I just formed the header you see (that has the "INCLUDE" string there) directly. Perhaps I should be using rauth to attach the file...
Without being able to see what code you're using with requests, I'm going to take a shot in the dark and tell you to remove setting your own Content-Type. You probably don't want that. It looks like you want multipart/form-data and requests will set that on its own if you stop fighting it.
It looks like you're missing the boundaries that QuickBooks is expecting (based on what you linked).
---------------------------acebdf13572468
Content-Disposition: form-data; name="file_content_01"; filename="IMG_0771.jpg"
Content-Type: image/jpeg
<#INCLUDE *Y:\Documents\IMG_0771.jpg*#>
---------------------------acebdf13572468--
The first and last line above seem to be what you're missing.
I need a live test server that accepts my requests for basic information via HTTP GET and also allows me to POST (even if it's really not doing anything). This is entirely for test purposes.
A good example is here. It easily accepts GET requests, but I need one that accepts POST requests as well.
Does anyone know of a server that I can send dummy test messages too?
https://httpbin.org/
It echoes the data used in your request for any of these types:
https://httpbin.org/anything Returns most of the below.
https://httpbin.org/ip Returns Origin IP.
https://httpbin.org/user-agent Returns user-agent.
https://httpbin.org/headers Returns header dict.
https://httpbin.org/get Returns GET data.
https://httpbin.org/post Returns POST data.
https://httpbin.org/put Returns PUT data.
https://httpbin.org/delete Returns DELETE data
https://httpbin.org/gzip Returns gzip-encoded data.
https://httpbin.org/status/:code Returns given HTTP Status code.
https://httpbin.org/response-headers?key=val Returns given response headers.
https://httpbin.org/redirect/:n 302 Redirects n times.
https://httpbin.org/relative-redirect/:n 302 Relative redirects n times.
https://httpbin.org/cookies Returns cookie data.
https://httpbin.org/cookies/set/:name/:value Sets a simple cookie.
https://httpbin.org/basic-auth/:user/:passwd Challenges HTTPBasic Auth.
https://httpbin.org/hidden-basic-auth/:user/:passwd 404'd BasicAuth.
https://httpbin.org/digest-auth/:qop/:user/:passwd Challenges HTTP Digest Auth.
https://httpbin.org/stream/:n Streams n–100 lines.
https://httpbin.org/delay/:n Delays responding for n–10 seconds.
There is http://ptsv2.com/
"Here you will find a server which receives any POST you wish to give it and stores the contents for you to review."
Webhook Tester is a great tool: https://webhook.site (GitHub)
Important for me, it showed the IP of the requester, which is helpful when you need to whitelist an IP address but aren't sure what it is.
nc one-liner local test server
Setup a local test server in one line under Linux:
nc -kdl localhost 8000
Sample request maker on another shell:
wget http://localhost:8000
then on the first shell you see the request showed up:
GET / HTTP/1.1
User-Agent: Wget/1.19.4 (linux-gnu)
Accept: */*
Accept-Encoding: identity
Host: localhost:8000
Connection: Keep-Alive
nc from the netcat-openbsd package is widely available and pre-installed on Ubuntu.
Tested on Ubuntu 18.04.
http://requestb.in was similar to the already mentioned tools and also had a very nice UI.
RequestBin gives you a URL that will collect requests made to it and let you inspect them in a human-friendly way.
Use RequestBin to see what your HTTP client is sending or to inspect and debug webhook requests.
Though it has been discontinued as of Mar 21, 2018.
We have discontinued the publicly hosted version of RequestBin due to ongoing abuse that made it very difficult to keep the site up reliably. Please see instructions for setting up your own self-hosted instance.
If you want a local test server that accepts any URL and just dumps the request to the console, you can use node:
const http = require("http");
const hostname = "0.0.0.0";
const port = 3000;
const server = http.createServer((req, res) => {
console.log(`\n${req.method} ${req.url}`);
console.log(req.headers);
req.on("data", function(chunk) {
console.log("BODY: " + chunk);
});
res.statusCode = 200;
res.setHeader("Content-Type", "text/plain");
res.end("Hello World\n");
});
server.listen(port, hostname, () => {
console.log(`Server running at http://localhost:${port}/`);
});
Save it in a file 'echo.js' and run it as follows:
$ node echo.js
Server running at http://localhost:3000/
You can then submit data:
$ curl -d "[1,2,3]" -XPOST http://localhost:3000/foo/bar
which will be shown in the server's stdout:
POST /foo/bar
{ host: 'localhost:3000',
'user-agent': 'curl/7.54.1',
accept: '*/*',
'content-length': '7',
'content-type': 'application/x-www-form-urlencoded' }
BODY: [1,2,3]
Have a look at PutsReq, it's similar to the others, but it also allows you to write the responses you want using JavaScript.
Here is one Postman echo: https://docs.postman-echo.com/
example:
curl --request POST \
--url https://postman-echo.com/post \
--data 'This is expected to be sent back as part of response body.'
response:
{"args":{},"data":"","files":{},"form":{"This is expected to be sent back as part of response body.":""},"headers":{"host":"postman-echo.com","content-length":"58","accept":"*/*","content-type":"application/x-www-form-urlencoded","user-agent":"curl/7.54.0","x-forwarded-port":"443","x-forwarded-proto":"https"},"json":{"...
You can run the actual Ken Reitz's httpbin server locally (under docker or on bare metal):
https://github.com/postmanlabs/httpbin
Run dockerized
docker pull kennethreitz/httpbin
docker run -p 80:80 kennethreitz/httpbin
Run directly on your machine
## install dependencies
pip3 install gunicorn decorator httpbin werkzeug Flask flasgger brotlipy gevent meinheld six pyyaml
## start the server
gunicorn -b 0.0.0.0:8000 httpbin:app -k gevent
Now you have your personal httpbin instance running on http://0.0.0.0:8000 (visible to all of your LAN)
Minimal Flask REST server
I wanted a server which returns predefined responses so I found that in this case it's simpler to use a minimal Flask app:
#!/usr/bin/env python3
# Install dependencies:
# pip3 install flask
import json
from flask import Flask, request, jsonify
app = Flask(__name__)
#app.route('/', methods=['GET', 'POST'])
def root():
# spit back whatever was posted + the full env
return jsonify(
{
'request.json': request.json,
'request.values': request.values,
'env': json.loads(json.dumps(request.__dict__, sort_keys=True, default=str))
}
)
#app.route('/post', methods=['GET', 'POST'])
def post():
if not request.json:
return 'No JSON payload! Expecting POST!'
# return the literal POST-ed payload
return jsonify(
{
'payload': request.json,
}
)
#app.route('/users/<gid>', methods=['GET', 'POST'])
def users(gid):
# return a JSON list of users in a group
return jsonify([{'user_id': i,'group_id': gid } for i in range(42)])
#app.route('/healthcheck', methods=['GET'])
def healthcheck():
# return some JSON
return jsonify({'key': 'healthcheck', 'status': 200})
if __name__ == "__main__":
with app.test_request_context():
app.debug = True
app.run(debug=True, host='0.0.0.0', port=8000)
I don't konw why all of the answers here make a very simple work very hard!
When there is a request on HTTP, actually a client will send a HTTP_MESSAGE to server (read about what is HTTP_MESSAGE) and you can make a server in just 2 simple steps:
Install netcat:
In many unix-based systems you have this already installed and if you have windows just google it , the installation process is really simple, you just need a nc.exe file and then you should copy the path of this nc.exe file to your path environment variable and check if every thing is OK with nc -h
Make a server which is listening on localhost:12345:
just type nc -l -p 12345 on your terminal and everything is done! (in mac nc -l 12345 tnx Silvio Biasiol)
Now you have a server which is listening on http://localhost:12345 , for example you can make a post request with axios If you are a js developer:
axios.post('http://localhost:12345', { firstName: 'Fred' })
or make your own xhr or make a form in a HTML file and submit it to server, sth. like:
<form action="http://localhost:12345" method="post">
or make a request with curl or wget or etc. Then check your terminal, a raw HTTP_MESSAGE should be appear on your terminal and you can start your happy hacking ;)
https://www.mockable.io. It has nice feature of getting endpoints without login (24h temporary account)
Create choose a free web host and put the following code
<h1>Request Headers</h1>
<?php
$headers = apache_request_headers();
foreach ($headers as $header => $value) {
echo "<b>$header:</b> $value <br />\n";
}
?>
I have created an open-source hackable local testing server that you can get running in minutes. You can create new API's, define your own response and hack it in any ways you wish to.
Github Link : https://github.com/prabodhprakash/localTestingServer
some online httpbin:
https://httpbin.org/
https://httpbingo.org/
https://quic.aiortc.org/httpbin/
get client ip, port, ua..
http://ifconfig.io/
get client ip, isp
https://www.cip.cc/
If you need or want a simple HTTP server with the following:
Can be run locally or in a network sealed from the public Internet
Has some basic auth
Handles POST requests
I built one on top of the excellent SimpleHTTPAuthServer already on PyPI. This adds handling of POST requests:
https://github.com/arielampol/SimpleHTTPAuthServerWithPOST
Otherwise, all the other options publicly available are already so good and robust.
You might don't need any web site for that, only open up the browser, press F12 to get access to developer tools > console, then in console write some JavaScript Code to do that.
Here I share some ways to accomplish that:
For GET request:
*.Using jQuery:
$.get("http://someurl/status/?messageid=597574445", function(data, status){
console.log(data, status);
});
For POST request:
Using jQuery $.ajax:
var url= "http://someurl/",
api_key = "6136-bc16-49fb-bacb-802358",
token1 = "Just for test",
result;
$.ajax({
url: url,
type: "POST",
data: {
api_key: api_key,
token1: token1
},
}).done(function(result) {
console.log("done successfuly", result);
}).fail(function(error) {
console.log(error.responseText, error);
});
Using jQuery, append and submit
var merchantId = "AA86E",
token = "4107120133142729",
url = "https://payment.com/Index";
var form = `<form id="send-by-post" method="post" action="${url}">
<input id="token" type="hidden" name="token" value="${merchantId}"/>
<input id="merchantId" name="merchantId" type="hidden" value="${token}"/>
<button type="submit" >Pay</button>
</div>
</form> `;
$('body').append(form);
$("#send-by-post").submit();//Or $(form).appendTo("body").submit();
Using Pure JavaScript:
`var api_key = "73736-bc16-49fb-bacb-643e58",
recipient = "095552565",
token1 = "4458",
url = 'http://smspanel.com/send/';`
``var form = `<form id="send-by-post" method="post" action="${url}">
<input id="api_key" type="hidden" name="api_key" value="${api_key}"/>
<input id="recipient" type="hidden" name="recipient" value="${recipient}"/>
<input id="token1" name="token1" type="hidden" value="${token1}"/>
<button type="submit" >Send</button>
</div>
</form>`;``
document.querySelector("body").insertAdjacentHTML('beforeend',form);
document.querySelector("#send-by-post").submit();
Or even using ASP.Net:
var url = "https://Payment.com/index";
Response.Clear();
var sb = new System.Text.StringBuilder();
sb.Append("<html>");
sb.AppendFormat("<body onload='document.forms[0].submit()'>");
sb.AppendFormat("<form action='{0}' method='post'>", url);
sb.AppendFormat("<input type='hidden' name='merchantId' value='{0}'>", "C668");
sb.AppendFormat("<input type='hidden' name='Token' value='{0}'>", "22720281459");
sb.Append("</form>");
sb.Append("</body>");
sb.Append("</html>");
Response.Write(sb.ToString());
Response.End();
I am not sure if anyone would take this much pain to test GET and POST calls. I took Python Flask module and wrote a function that does something similar to what #Robert shared.
from flask import Flask, request
app = Flask(__name__)
#app.route('/method', methods=['GET', 'POST'])
#app.route('/method/<wish>', methods=['GET', 'POST'])
def method_used(wish=None):
if request.method == 'GET':
if wish:
if wish in dir(request):
ans = None
s = "ans = str(request.%s)" % wish
exec s
return ans
else:
return 'This wish is not available. The following are the available wishes: %s' % [method for method in dir(request) if '_' not in method]
else:
return 'This is just a GET method'
else:
return "You are using POST"
When I run this, this follows:
C:\Python27\python.exe E:/Arindam/Projects/Flask_Practice/first.py
* Restarting with stat
* Debugger is active!
* Debugger PIN: 581-155-269
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
Now lets try some calls. I am using the browser.
http://127.0.0.1:5000/method
This is just a GET method
http://127.0.0.1:5000/method/NotCorrect
This wish is not available. The following are the available wishes:
['application', 'args', 'authorization', 'blueprint', 'charset', 'close', 'cookies', 'data', 'date', 'endpoint', 'environ', 'files', 'form', 'headers', 'host', 'json', 'method', 'mimetype', 'module', 'path', 'pragma', 'range', 'referrer', 'scheme', 'shallow', 'stream', 'url', 'values']
http://127.0.0.1:5000/method/environ
{'wsgi.multiprocess': False, 'HTTP_COOKIE': 'csrftoken=YFKYYZl3DtqEJJBwUlap28bLG1T4Cyuq', 'SERVER_SOFTWARE': 'Werkzeug/0.12.2', 'SCRIPT_NAME': '', 'REQUEST_METHOD': 'GET', 'PATH_INFO': '/method/environ', 'SERVER_PROTOCOL': 'HTTP/1.1', 'QUERY_STRING': '', 'werkzeug.server.shutdown': , 'HTTP_USER_AGENT': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.71 Safari/537.36', 'HTTP_CONNECTION': 'keep-alive', 'SERVER_NAME': '127.0.0.1', 'REMOTE_PORT': 49569, 'wsgi.url_scheme': 'http', 'SERVER_PORT': '5000', 'werkzeug.request': , 'wsgi.input': , 'HTTP_HOST': '127.0.0.1:5000', 'wsgi.multithread': False, 'HTTP_UPGRADE_INSECURE_REQUESTS': '1', 'HTTP_ACCEPT': "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8", 'wsgi.version': (1, 0), 'wsgi.run_once': False, 'wsgi.errors': ", mode 'w' at 0x0000000002042150>", 'REMOTE_ADDR': '127.0.0.1', 'HTTP_ACCEPT_LANGUAGE': 'en-US,en;q=0.8', 'HTTP_ACCEPT_ENCODING': 'gzip, deflate, sdch, br'}
Another one that offers some customization and is easy to use (no install, signup) is https://beeceptor.com .
You create a endpoint, makes a initial request to it and can tweak the responses.
I am using this REST API all the time: https://restful-api.dev
It stores the created objects indefinitely.
Also, the schema is quite flexible, you can pass any JSON data.
I am a Front-End developer and is very useful when I need to create some sample data. This is the only one I could find that does it for free without any registration or tokens.
Just set one up yourself. Copy this snippet to your webserver.
echo "<pre>";
print_r($_POST);
echo "</pre>";
Just post what you want to that page. Done.